版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第1章引言在人們逐漸追求精神文化的過(guò)程中,聽(tīng)音樂(lè)也漸漸成為了一種比較廣泛的興趣愛(ài)好。如今在互聯(lián)網(wǎng)當(dāng)中,音頻播放器種類(lèi)眾多。音樂(lè)播放器屬于多媒體軟件,可以進(jìn)行各式各樣的文件播放,同時(shí)包含了多種格式內(nèi)容,例如MP3等。其通常操作過(guò)程比較簡(jiǎn)單,而且界面較為美觀,能夠讓人真正進(jìn)入到放松的音樂(lè)空間當(dāng)中。音樂(lè)播放器在本質(zhì)上其實(shí)屬于一種操作界面,其根本內(nèi)容是音頻解碼器,主要是對(duì)于不同種類(lèi)的編碼后的音頻所進(jìn)行的解碼。許多音樂(lè)播放器對(duì)于各類(lèi)格式都比較支持,其原因是音頻播放器本身能夠?qū)τ诓煌N類(lèi)的解碼器進(jìn)行有效解碼,并且使所有的播放頁(yè)面達(dá)到統(tǒng)一,讓使用者對(duì)于音樂(lè)有更加深刻的感受。由于音樂(lè)播放器本身存在固定的方式進(jìn)行音頻解碼,而且其原理層面僅僅是對(duì)于解碼器進(jìn)行打包,所以在整體上來(lái)說(shuō),一切播放器的播放音質(zhì)都可能是完全一樣的,并沒(méi)有音質(zhì)方面的區(qū)別。不過(guò),某些音樂(lè)播放器為了突出自身的播放水平,會(huì)以解碼器作為前提,進(jìn)一步進(jìn)行DSP插件的添加,滿(mǎn)足受眾的需求,這可以說(shuō)是對(duì)于原本音樂(lè)展開(kāi)扭曲或者轉(zhuǎn)換的過(guò)程,但其實(shí)僅僅是對(duì)于細(xì)節(jié)的過(guò)濾或者將音調(diào)降低等,在宣傳過(guò)程中,可能會(huì)宣傳成為音質(zhì)的美化等方式,但其實(shí),這種方式在本身上是對(duì)于音樂(lè)的破壞,其能夠讓某些音樂(lè)變得更加好聽(tīng),但對(duì)于大部分音樂(lè)來(lái)說(shuō),卻會(huì)導(dǎo)致音質(zhì)水平的降低。因此,有必要了解到的是,作為音樂(lè)播放器本身,其所具備的操作界面或者擴(kuò)展性?xún)?nèi)容,才是真正屬于播放器本身的特色。如今許多商業(yè)播放軟件,可能有非常絢麗的界面,或者說(shuō)在操作方面存在與眾不同的表現(xiàn),但通常而言并不具備拓展性,對(duì)于格式支持并不是很多。同時(shí),在開(kāi)源播放軟件方面通常能夠獲得一定程度的拓展,對(duì)于不同種類(lèi)的音樂(lè)格式予以支持,不過(guò)通常而言界面比較樸素,客戶(hù)無(wú)法從中感受到充分的吸引力。國(guó)外的音樂(lè)播放器通常包括realplayer和微軟系統(tǒng)本身自帶的播放器,但是通常在國(guó)內(nèi)的使用頻率并不高,而在國(guó)內(nèi)音樂(lè)市場(chǎng)當(dāng)中,酷狗、網(wǎng)易云、QQ音樂(lè)等播放器占據(jù)了大量市場(chǎng),而且通過(guò)一定的軟件更新和升級(jí),無(wú)論是播放器本身的功能還是給用戶(hù)帶來(lái)的體驗(yàn)方面都有了不錯(cuò)的發(fā)展。如今,國(guó)內(nèi)進(jìn)行了兩個(gè)主要方向的音頻研究,首先是胡守超以Python語(yǔ)言作為基礎(chǔ),通過(guò)音頻的捕獲和頻率分析所展開(kāi)的設(shè)計(jì),通過(guò)編程語(yǔ)言分析相關(guān)音頻數(shù)據(jù),并對(duì)于音頻數(shù)據(jù)內(nèi)容進(jìn)行有效采集,進(jìn)行音頻波譜以及頻率的有效顯示。另外也是以Python音頻數(shù)據(jù)作為基礎(chǔ),通過(guò)對(duì)于聲音文件本身格式以及播放特性的轉(zhuǎn)換,對(duì)于不同的音頻文件展開(kāi)對(duì)應(yīng)分離以及合成,同時(shí)對(duì)不同音樂(lè)之間所具有的特征展開(kāi)有效分析,有效改變?cè)韭曇舢?dāng)中出現(xiàn)的采樣寬度、速率以及編碼等內(nèi)容。國(guó)外使用頻率較高的專(zhuān)業(yè)播放器,具備多媒體解析功能以及軟件編輯功能,來(lái)自于Adobe公司所開(kāi)發(fā)的相關(guān)內(nèi)容,其主要設(shè)計(jì)目標(biāo)是音頻以及視頻專(zhuān)業(yè)人員,通常他們使用于照相師、后期制作以及廣播等方面,軟件本身具備音頻混合、音頻編輯、音頻控制以及相關(guān)頻率的處理等功能特性。此次研究過(guò)程中,以CoolEditPro軟件本身具備的功能作為基礎(chǔ),借助其軟件運(yùn)用,同時(shí)通過(guò)Python語(yǔ)言的結(jié)合使用,以及利用程序編輯器和專(zhuān)業(yè)工具包,進(jìn)行音頻播放器的設(shè)計(jì)以及實(shí)現(xiàn),播放器本身能夠進(jìn)行各種格式的音頻播放,并且能夠進(jìn)行wava文件的波形顯示等一系列的特殊功能。第2章軟件開(kāi)發(fā)環(huán)境與開(kāi)發(fā)工具2.1Eclipse軟件簡(jiǎn)介Eclipse本身屬于一種集成式的開(kāi)發(fā)環(huán)境,同時(shí)具備跨平臺(tái)的作用。一開(kāi)始這個(gè)平臺(tái)的作用是java開(kāi)發(fā),不過(guò)到如今為止,已經(jīng)有很多人利用插件進(jìn)行其他語(yǔ)言的開(kāi)發(fā),比如c語(yǔ)言以及Python??梢哉f(shuō)此軟件僅僅屬于一種平臺(tái),屬于開(kāi)發(fā)過(guò)程中的框架,而通過(guò)這些插件支持,相對(duì)來(lái)說(shuō)使整個(gè)平臺(tái)的靈活性大大提升,對(duì)于比較固定的軟件而言,這種靈活性是非常難得的。在此平臺(tái)當(dāng)中,插件本身也是組件化的存在,作為客戶(hù)而言,在使用過(guò)程中,可以通過(guò)插件滿(mǎn)足相關(guān)附加功能,比方說(shuō)不僅僅對(duì)于java語(yǔ)言有一定的支持程度,同時(shí)對(duì)其他語(yǔ)言而言,也能夠予以支持。另外,如今已經(jīng)存在的插件已經(jīng)可以支持多種編程語(yǔ)言的開(kāi)發(fā),并且可以進(jìn)行相關(guān)數(shù)據(jù)庫(kù)開(kāi)發(fā),比如C語(yǔ)言、C++以及本文當(dāng)中所使用的Python語(yǔ)言等。同時(shí),作為該平臺(tái)本身,存在一定的插件架構(gòu),能夠支持各類(lèi)擴(kuò)展功能,比如配置管理等,而并不只是對(duì)于不同種類(lèi)的編程語(yǔ)言予以支持。作為Eclipse平臺(tái)本身,其所具備的設(shè)計(jì)理念在于所有的東西都屬于插件的一部分。作為平臺(tái)本身,其核心內(nèi)容并不是很多,而另外的功能都以核心為基礎(chǔ),同時(shí)以插件的方式進(jìn)行附著。此外,其中內(nèi)核成分包含了圖形、環(huán)境插件以及java語(yǔ)言等基礎(chǔ)內(nèi)容。同時(shí),作為軟件開(kāi)發(fā)人員而言,通過(guò)SDK進(jìn)行相應(yīng)的組建合并,能夠讓使用者更方便的進(jìn)行工具下載。在合并之后可以提供具備豐富特性的開(kāi)發(fā)環(huán)境,同時(shí)作為開(kāi)發(fā)者而言,則能夠有效進(jìn)行工具建設(shè),并且集成到平臺(tái)環(huán)境當(dāng)中。SDK本身包含了平臺(tái)自身的工具以及其他軟件當(dāng)中的系列工具內(nèi)容,這些工具主要是源代碼已經(jīng)開(kāi)放的相關(guān)平臺(tái)。另外,作為項(xiàng)目生產(chǎn)過(guò)程中,可以通過(guò)GPL進(jìn)行有效發(fā)布,而作為組件來(lái)說(shuō),則有它們本身的許可協(xié)議等內(nèi)容。2.2Python語(yǔ)言簡(jiǎn)介Python屬于解釋型,且能夠面向?qū)ο蟮某绦蛘Z(yǔ)言,同時(shí)此程序語(yǔ)言屬于動(dòng)態(tài)類(lèi)型。從1990年開(kāi)始發(fā)展到如今,此類(lèi)語(yǔ)言已經(jīng)在系統(tǒng)管理任務(wù)當(dāng)中獲得了非常廣泛的使用,同時(shí)也在web編程當(dāng)中得到了良好的應(yīng)用效果,甚至可以說(shuō)是目前受歡迎程度最廣的一項(xiàng)涉及語(yǔ)言。因?yàn)樵撜Z(yǔ)言本身具備可擴(kuò)展以及簡(jiǎn)潔特性,在國(guó)外通過(guò)這種語(yǔ)言進(jìn)行科學(xué)計(jì)算的機(jī)構(gòu)數(shù)量漸漸增加,尤其是不少知名大學(xué)已經(jīng)采取此語(yǔ)言進(jìn)行程序課程的教育。同時(shí),許多開(kāi)源科學(xué)計(jì)算過(guò)程中都提供了相應(yīng)的接口,可以進(jìn)行此類(lèi)語(yǔ)言的調(diào)用。而針對(duì)Python本身,科學(xué)擴(kuò)展庫(kù)數(shù)量可以說(shuō)是非常多,比如numpy以及scipy等,通過(guò)這些擴(kuò)展庫(kù)能夠讓語(yǔ)言本身獲得數(shù)值運(yùn)算等功能,或者進(jìn)行數(shù)組處理和繪圖功能的實(shí)現(xiàn)。所以總體而言,該語(yǔ)言本身和語(yǔ)言擴(kuò)展功能共同構(gòu)成相應(yīng)的開(kāi)發(fā)環(huán)境,有利于科研人員進(jìn)行數(shù)據(jù)處理,同時(shí)有利于工程技術(shù)人員進(jìn)行相應(yīng)你的圖標(biāo)制作,或者進(jìn)行科學(xué)程序的有效開(kāi)發(fā)。另外,追溯到源頭可以得知Python設(shè)計(jì)者本身在語(yǔ)法方面加強(qiáng)了限制性,可以說(shuō)是在很大程度上糾正了一些不良習(xí)慣,避免由于疏漏導(dǎo)致的程序錯(cuò)誤,比如對(duì)于if語(yǔ)句而言,如果下一行沒(méi)有縮進(jìn)的話(huà),在這個(gè)平臺(tái)當(dāng)中的編譯是無(wú)法被通過(guò)的,這也就是眾所周知的此語(yǔ)言本身具備的縮進(jìn)規(guī)則。此外,Python與其他許多語(yǔ)言,比如C++等語(yǔ)言存在的主要區(qū)別在于:模塊本身?yè)碛械慕泳€(xiàn),并不是通過(guò)某些符號(hào)表達(dá)所進(jìn)行的定義,在許多語(yǔ)言當(dāng)中模塊接線(xiàn)通常需要特殊字符進(jìn)行隔離,但是在Python當(dāng)中,則是由首字符所在的位置進(jìn)行確定的。這一點(diǎn)的設(shè)定引起了不少人的不滿(mǎn),主要原因是由于C++等語(yǔ)言出現(xiàn)之后,逐漸將語(yǔ)法本身具有的含義不體現(xiàn)在字符的排列方面,而且認(rèn)為這種區(qū)分屬于程序語(yǔ)言在逐步進(jìn)步的過(guò)程。但是需要承認(rèn)的是,Python平臺(tái)當(dāng)中的這些要求,讓整體程序的美觀度大大提升,其中包含了一些模塊的使用,尤其是if以及for等定義的強(qiáng)制縮進(jìn)等要求,這種強(qiáng)制性可以說(shuō)是帶來(lái)了一定的好處。而且,Python作為一種語(yǔ)言,本身是面對(duì)某些對(duì)象進(jìn)行使用的,其中包括了模塊、字符串以及函數(shù)等,而且具備一定的繼承性和派生性等,在這個(gè)過(guò)程中,對(duì)于源代碼重復(fù)使用有一定的幫助。同時(shí),平臺(tái)本身對(duì)于動(dòng)態(tài)特性和運(yùn)算符的重新載入有一定的支持度,相比較一些比較傳統(tǒng)的語(yǔ)言而言,在函數(shù)設(shè)計(jì)方面,該平臺(tái)并沒(méi)有提供全方位的支持,而是比較片面的作用。在具體執(zhí)行過(guò)程中,Python平臺(tái)本身會(huì)執(zhí)行后綴名為py的文件,并且將其中存在的源代碼進(jìn)行編譯,使之全部成為字節(jié)碼,之后通過(guò)虛擬機(jī)進(jìn)行字節(jié)碼的有效執(zhí)行。另外,平臺(tái)本身能夠通過(guò)交互模式進(jìn)行運(yùn)行,也就是說(shuō)可以在不同系統(tǒng)當(dāng)中進(jìn)行操作,而并不是僅僅局限于Windows或者某種系統(tǒng),一些主流系統(tǒng)都能夠在命令模式之下進(jìn)行此平臺(tái)的環(huán)境命令,或者通過(guò)指令下達(dá),就可以有效完成相關(guān)操作過(guò)程。2.3所用到的python工具包在整體開(kāi)發(fā)進(jìn)程當(dāng)中,Python平臺(tái)當(dāng)中使用了各類(lèi)工具包,比如跨平臺(tái)所進(jìn)行的應(yīng)用程式框架等程序pyside,其可以說(shuō)是屬于平臺(tái)本身存在的綁定版本,另外還有一些工具包能夠進(jìn)行波形圖的繪制,以及計(jì)算其中所存在的音頻數(shù)據(jù)等內(nèi)容,在此開(kāi)發(fā)過(guò)程中得到了廣泛的應(yīng)用。同時(shí)在此次設(shè)計(jì)過(guò)程中,還需要通過(guò)Pysideuic進(jìn)一步轉(zhuǎn)換相應(yīng)的ui文件,使之成為py后綴名的文件內(nèi)容。第3章軟件界面窗口的實(shí)現(xiàn)3.1QtDesigner軟件簡(jiǎn)介QtDesigner屬于GUI的工具內(nèi)容,通過(guò)這項(xiàng)工具的使用,能夠使QT程序的編寫(xiě)速度大大加強(qiáng),另外,通過(guò)此軟件的使用,能夠產(chǎn)生所見(jiàn)所得的效果,避免盲目進(jìn)行代碼編寫(xiě)之后出現(xiàn)各類(lèi)問(wèn)題,在編寫(xiě)過(guò)程中,可以通過(guò)QT程序產(chǎn)生界面代碼,而在增加系列功能之后,就能夠妥善完成工具編寫(xiě)。具體操作步驟是通過(guò)此類(lèi)程序進(jìn)行頁(yè)面搭建,在搭建之后保存相應(yīng)的UI文件,之后通過(guò)命令解釋器進(jìn)行文件轉(zhuǎn)換,也就是上文當(dāng)中所提到的將ui文件向py文件進(jìn)行轉(zhuǎn)換。3.2軟件整體界面的繪制需要重視的是,在整體界面當(dāng)中并非僅僅包含一部分內(nèi)容,而是由上半部分、中部以及下半部分共同構(gòu)成,其中上半部分屬于播放器,包含了文件選擇、時(shí)間編輯以及播放或者停止等,同時(shí)可以在這一部分進(jìn)行音量的調(diào)節(jié)以及波形的具體條件,而且也能夠進(jìn)行快進(jìn)和快退等操作內(nèi)容。而中部則屬于動(dòng)態(tài)波形區(qū)域,可以進(jìn)行相關(guān)波形的展示。下半部分則屬于靜態(tài)波形區(qū),在音頻播放的過(guò)程中也具有特定的效果,但總體功能還是集中在頁(yè)面的最上方。在具體繪制的過(guò)程中,可以在運(yùn)行軟件之后,新建窗口,同時(shí)按照原本的設(shè)計(jì)路徑進(jìn)行功能的添加以及繪制,分別包括時(shí)間的編輯按鈕,以及進(jìn)行文件選擇,文本框的粘貼,之后則設(shè)置播放按鈕以及暫停按鈕,同時(shí)為了方便使用,還可以設(shè)置停止播放按鈕,隨后對(duì)于音量大小進(jìn)行調(diào)節(jié),可以設(shè)置按鈕或者進(jìn)度條等,再之后通過(guò)放大鏡作為觸發(fā)模式,針對(duì)波形的大小展開(kāi)調(diào)節(jié),而后實(shí)現(xiàn)快進(jìn)與快退等模式,通過(guò)時(shí)間以及進(jìn)度條等觀察音樂(lè)具體的播放情況,在這些功能全部添加之后,也就完成了上半部分的界面繪制,不過(guò)還需要將整體布局設(shè)置成水平模式,從而實(shí)現(xiàn)如圖所示的構(gòu)造。之后,為了實(shí)現(xiàn)其他部分的窗口功能和內(nèi)容,可以重新建立窗口,并進(jìn)行兩個(gè)部分的劃分,上半部分是播放過(guò)程中的動(dòng)態(tài)波形顯示,而下半部分則是保持不變的整體波形顯示,通過(guò)這種操作也就完成了整體的頁(yè)面設(shè)計(jì)過(guò)程。圖3.2設(shè)計(jì)頁(yè)面第4章音頻解析與播放功能的實(shí)現(xiàn)4.1phonon模塊簡(jiǎn)介隨著科學(xué)技術(shù)的發(fā)展,音頻格式也逐漸增多,如今在音頻格式領(lǐng)域已經(jīng)包含了MP3、WMA、WAV等常見(jiàn)格式,以及VQF和APE等不是非常常見(jiàn)的格式。面對(duì)如此復(fù)雜的內(nèi)容,通過(guò)調(diào)用工具包當(dāng)中的模塊就能夠?qū)τ谒幸纛l格式進(jìn)行有效解析,而且可以在調(diào)用相應(yīng)模塊之后,有效實(shí)現(xiàn)各種音頻格式的播放。4.2功能具體實(shí)現(xiàn)過(guò)程音頻格式當(dāng)中包含如下幾個(gè)方面的內(nèi)容,第一是獲取源文件,之后是實(shí)現(xiàn)播放功能、暫停功能以及停止等具體功能。因?yàn)槠脚_(tái)本身屬于集成且開(kāi)源的類(lèi)型,其中包含了許多種類(lèi)的API等內(nèi)容,所以只需要進(jìn)行普通函數(shù)調(diào)用就能夠有效實(shí)現(xiàn)相關(guān)功能,而在此次設(shè)計(jì)過(guò)程中使用了如下內(nèi)容:MediaObject、MediaSource、MusicCategory、createPath、PlayingState、StoppedState、LoadingState、BufferingState、ErrorState。之后利用代碼以及注釋對(duì)于相關(guān)過(guò)程展開(kāi)有效分析:classPlayer(QtGui.QWidget):def__init__(self,parent=None):QtGui.QWidget.__init__(self,parent)self.ui=Ui_toolBoxWidget()#實(shí)例化Ui_toolBoxWidget類(lèi)self.ui.setupUi(self)#調(diào)用setupUi函數(shù)self.media=Phonon.MediaObject(self)#實(shí)例化MediaObject類(lèi)self.media.setCurrentSource(Phonon.MediaSource())#設(shè)置當(dāng)前源文件self.media.setTickInterval(100)#設(shè)置音頻解析間隔self.output=Phonon.AudioOutput(Phonon.MusicCategory,self)#音頻輸出類(lèi)型Phonon.createPath(self.media,self.output)#選擇默認(rèn)音頻路徑self.ui.volumeSlider_music.setAudioOutput(self.output)#鏈接到音量調(diào)節(jié)功能self.ui.seekSlider_musicProgress.setMediaObject(self.media)#鏈接到進(jìn)度條self.ui.lcdNumber.display("00:00")#鏈接到時(shí)間顯示self.media.stateChanged.connect(self.stateChanged)#鏈接到狀態(tài)轉(zhuǎn)換函數(shù)self.media.tick.connect(self.tick)#鏈接到顯示時(shí)間方式函數(shù)self.ui.pushButton_musicPlay.clicked.connect(self.changePlayPause)#鏈接到播放暫停函數(shù)self.ui.pushButton_musicStop.clicked.connect(self.changeStop)#鏈接到停止函數(shù)self.ui.pushButton_chooseMusicFile.clicked.connect(self.handleButtonChoose)#鏈接到文件選擇函數(shù)self.ui.timeEdit_music.timeChanged.connect(self.timeEditTimeChanged)#鏈接到時(shí)間編輯函數(shù)self.path=None#路徑初始化為空self.signal=FileChoosedSignal()#實(shí)例化FileChoosedSignal類(lèi)deftimeEditTimeChanged(self,time):miliSec=(((time.hour()*60+time.minute())*60)+time.second())*1000print'miliSec',miliSecself.media.seek(miliSec)#時(shí)間編輯defgetPlayerMedia(self):returnself.media#獲取源文件defhandleButtonChoose(self):dialog=QtGui.QFileDialog(self)dialog.setFileMode(QtGui.QFileDialog.ExistingFile)ifdialog.exec_()==QtGui.QDialog.Accepted:self.path=dialog.selectedFiles()[0]self.media.setCurrentSource(Phonon.MediaSource(self.path))self.ui.lineEdit_musicFilePath.setText(self.path)dialog.deleteLater()#選擇文件deftick(self,time):displayTime=QtCore.QTime(0,(time/60000)%60,(time/1000)%60)self.ui.lcdNumber.display(displayTime.toString('mm:ss'))self.signal.TimeNowChanged.emit(time)#時(shí)間顯示方式defchangePlayPause(self):ifself.path==None:msgBox=QtGui.QMessageBox(self)msgBox.setText("pleasechooseamusicfilefirst.")msgBox.setStandardButtons(QtGui.QMessageBox.Ok)msgBox.exec_()returnifself.media.state()==Phonon.PlayingState:self.media.pause()elifself.media.state()==Phonon.StoppedState:self.media.play()self.signal.fileChoosedSignal.emit()else:self.media.play()#播放暫停defchangeStop(self):self.media.stop()#停止defstateChanged(self,newstate,oldstate):ifnewstate==Phonon.PlayingState:self.ui.pushButton_musicPlay.setIcon(QtGui.QIcon(":/Image/Image/pause.png"))elif(newstate!=Phonon.LoadingStateandnewstate!=Phonon.BufferingState):self.ui.pushButton_musicPlay.setIcon(QtGui.QIcon(":/Image/Image/play.png"))ifnewstate==Phonon.ErrorState:print('ERROR:playiswrong:%s'%self.media.errorString())#狀態(tài)轉(zhuǎn)換classFileChoosedSignal(QtCore.QObject):fileChoosedSignal=QtCore.Signal()TimeNowChanged=QtCore.Signal(int)#創(chuàng)建兩個(gè)信號(hào)圖4.2音頻區(qū)第5章波形顯示的實(shí)現(xiàn)5.1對(duì)WAV文件獲取數(shù)據(jù)波形本身是利用解析得知的數(shù)據(jù)在波形區(qū)當(dāng)中的位置進(jìn)行描點(diǎn),而通過(guò)描點(diǎn)進(jìn)行集合,將會(huì)產(chǎn)生連續(xù)波形等內(nèi)容。在此次設(shè)計(jì)過(guò)程中,可以利用wava模塊對(duì)于具體數(shù)據(jù)進(jìn)行解析,可以返回有關(guān)數(shù)據(jù)并進(jìn)行識(shí)別。最終可以依照已經(jīng)得到的數(shù)據(jù)信息進(jìn)行波形繪制。對(duì)于Python而言,模塊本身提供了相應(yīng)的接口進(jìn)行使用,其能夠?qū)τ谖募?dāng)中的參數(shù)進(jìn)行解析,比如頻率、寬度以及幀數(shù)等內(nèi)容。通過(guò)類(lèi)似數(shù)據(jù)以及結(jié)合相關(guān)工具進(jìn)行wava文件繪制。依照上述內(nèi)容可以了解到,模塊本身存在缺點(diǎn),比如不支持解壓等特性,因此在此次設(shè)計(jì)過(guò)程中,僅僅能夠進(jìn)行wava波形的解壓,如下可以利用代碼更好地實(shí)現(xiàn)相關(guān)內(nèi)容:第一步是進(jìn)行初始化得到對(duì)應(yīng)的文件內(nèi)容。self.audio=wave.open(path,'r')#對(duì)文件進(jìn)行只讀操作self.nchannels,self.sampwidth,self.framerate,self.nframes,ptype,pname=self.audio.getparams()#獲取文件各項(xiàng)參數(shù)然后進(jìn)行讀取操作,defread(self,size):data=self.audio.readframes(size)#size為總幀數(shù)sw=self.audio.getsampwidth()#獲取采樣寬度data=numpy.frombuffer(data,dtype=numpy.dtype("i%d"%sw))#用numpy工具進(jìn)行科學(xué)計(jì)算nc=self.audio.getnchannels()ifnc>1:left=data[0::nc]right=data[1::nc]sample=[left,right]else:sample=datareturnsample+#返回值也就是在波形繪制過(guò)程中的數(shù)據(jù)需求。5.2根據(jù)音頻數(shù)據(jù)繪制音樂(lè)波形通過(guò)上述模塊能夠獲得畫(huà)圖當(dāng)中的具體數(shù)據(jù)內(nèi)容,在畫(huà)圖當(dāng)中使用的工具是matplot包。而此內(nèi)容通常是在平臺(tái)代碼當(dāng)中展開(kāi),進(jìn)行2D界面繪圖的有效制作,同時(shí)促進(jìn)科學(xué)計(jì)算性能的有效優(yōu)化。5.2.1音頻數(shù)據(jù)全部波形在音頻數(shù)據(jù)波形當(dāng)中,能夠使完整的wav文件獲得轉(zhuǎn)換,轉(zhuǎn)換的是所有的數(shù)據(jù)內(nèi)容,而結(jié)果是一切波形。在此模塊當(dāng)中,通過(guò)五項(xiàng)函數(shù)進(jìn)行調(diào)用,分別包括初始化繪圖、依照數(shù)據(jù)進(jìn)行跟蹤區(qū)的有效刷新、依照數(shù)據(jù)對(duì)時(shí)間信息進(jìn)行刷新以及展開(kāi)屬性設(shè)置。如下是具體的代碼操作:deffreshLeftAndWidthFromUpperPlot(self,leftFrame,rightFrame):ifself.ax==None:Return#print(22%250)else:self.leftDot=leftFrame/self.zipRateself.rightDot=rightFrame/self.zipRatexy=#print(22%250)np.array([[self.leftDot,0.],[self.leftDot,1.],[self.rightDot,1.],[self.rightDot,0.],[self.leftDot,0.]])self.span.set_xy(xy)self.canvas.draw()#print(22%250)#根據(jù)實(shí)時(shí)數(shù)據(jù)來(lái)刷新矩形跟蹤區(qū)deffreshCurrentTimeFromUpperPlot(self,frameNow):ifhasattr(self,'vline'):self.vline.set_xdata(frameNow/self.zipRate)self.canvas.draw()#print(22%250)#根據(jù)實(shí)時(shí)數(shù)據(jù)來(lái)刷新當(dāng)前時(shí)間信息defdrawInit(self,waveData):self.clf()self.plotDataDict=self.plotDataProcess(waveData)self.ax=self.add_axes([0.1,0.1,0.8,0.8])#print(22%250)self.vline=self.ax.axvline(x=10,color='red',zorder=3)self.span=self.ax.axvspan(0,0,facecolor='g',alpha=0.5,zorder=2)self.plotFunc(self.plotDataDict)self.ax.set_xlim(0,self.dotsInScreen)self.canvas.draw()#繪圖區(qū)初始化defplotFunc(self,plotDataDict):xarray=np.arange(self.dotsInScreen)ifplotDataDict.has_key('y_mean_2'):ymax=plotDataDict['y_max']ymin=plotDataDict['y_min']#print(22%250)ymean=plotDataDict['y_mean']ymean2=plotDataDict['y_mean_2']self.fillPlot=self.ax.fill_between(xarray,ymax,y2=ymin,color='#108070',zorder=0)self.linePlot=self.ax.plot(xarray,ymean,'pink',xarray,ymean2,'y',zorder=1)else:#print(22%250)ymax=plotDataDict['y_max']ymin=plotDataDict['y_min']ymean=plotDataDict['y_mean']self.fillPlot=self.ax.fill_between(xarray,ymax,y2=ymin,zorder=0)self.linePlot=self.ax.plot(xarray,ymean,'b',zorder=1)#繪圖區(qū)屬性設(shè)置defplotDataProcess(self,waveData):ifisinstance(waveData,list):dataOne=waveData[0]#print(22%250)dataTwo=waveData[1]dataLength=len(dataOne)numchunks=self.dotsInScreenchunksize=dataLength//numchunksself.zipRate=chunksize#print(22%250)team_1=dataOne[:chunksize*numchunks].reshape((-1,chunksize))team_2=dataTwo[:chunksize*numchunks].reshape((-1,chunksize))max_1=team_1.max(axis=1)max_2=team_2.max(axis=1)#print(22%250)max_1_2=np.maximum(max_1,max_2)min_1=team_1.min(axis=1)min_2=team_2.min(axis=1)#print(22%250)min_1_2=np.minimum(min_1,min_2)mean_1=team_1.mean(axis=1)mean_2=team_2.mean(axis=1)plotDataDict=dict(y_max=max_1_2,y_min=min_1_2,y_mean=mean_1,y_mean_2=mean_2)else:#print(22%250)dataOne=waveDatadataLength=len(dataOne)numchunks=self.dotsInScreenchunksize=dataLength//numchunksself.zipRate=chunksize#print(22%250)team_1=dataOne[:chunksize*numchunks].reshape((-1,chunksize))max_1=team_1.max(axis=1)min_1=team_1.min(axis=1)mean_1=team_1.mean(axis=1)plotDataDict=dict(y_max=max_1,y_min=min_1,y_mean=mean_1)returnplotDataDict#print(22%250)利用相關(guān)函數(shù)能夠得到音頻當(dāng)中的全部波形內(nèi)容:圖5.1靜態(tài)波形區(qū)5.2.2當(dāng)前時(shí)間段波形在上述操作當(dāng)中,獲得了來(lái)自音頻的整體波形,但屬于第三個(gè)區(qū)域的靜態(tài)內(nèi)容,而如果想要讓其得到動(dòng)態(tài)有效的顯示,還需要展開(kāi)進(jìn)一步的研究。與靜態(tài)波形相同的是,動(dòng)態(tài)波形也是在wave模塊當(dāng)中所獲得的信息,并且通過(guò)軟件進(jìn)行繪制。但存在區(qū)別的是,動(dòng)態(tài)模型需要實(shí)時(shí)刷新,并且獲得實(shí)時(shí)數(shù)據(jù)跟蹤等內(nèi)容。在這一方面可以用到的函數(shù)數(shù)量更多,比如波形的更新、時(shí)間的同步以及繪圖初始化等操作,并且能夠進(jìn)行坐標(biāo)清除和屬性設(shè)置,更進(jìn)一步獲得動(dòng)態(tài)的數(shù)據(jù)跟蹤,同時(shí)具備波形的縮小以及放大等功能,實(shí)現(xiàn)音樂(lè)的快速調(diào)整,對(duì)于波形進(jìn)行放大以及縮小。具體程序代碼如下:defmediaTimeChanged(self,time):self.currentTime_ms=int(time)self.fresh()self.signal.freshScreenTime.emit(time)#源文件時(shí)間同步deffresh(self):#print(22%250)ifnothasattr(self,'ax'):returnifhasattr(self,'pressX')andnotself.pressX==None:self.currentTime_ms=self.media.currentTime()frameNow=self.currentTime_ms*self.framerate/1000framesInScreen=self.secondsInScreen*self.frameratedotNow=frameNow/self.zipRateself.signal.freshLowerPlotCurrentTime.emit(frameNow)ifdotNow>=self.leftDot+self.dotsInScreen*3/2ordotNow<=self.leftDot-self.dotsInScreen/2:print'or'#print(22%250)print'self.leftdot=',self.leftDotprint'dotNow=',dotNownumberOfScreens=(dotNow-self.dotsInScreen/2)//self.dotsInScreenself.leftDot=numberOfScreens*self.dotsInScreennpSlice=np.arange(self.leftDot,self.leftDot+self.dotsInScreen)self.plotFunc(npSlice)self.clearAxes()#print(22%250)ifself.leftDot+self.dotsInScreen*3/2>dotNow>self.leftDot+self.dotsInScreen/2:print'draw>>'npSlice=np.arange(self.leftDot+self.dotsInScreen,self.leftDot+2*self.dotsInScreen)self.plotFunc(npSlice)self.clearAxes()#print(22%250)self.leftDot+=self.dotsInScreenself.ax.set_xlim(dotNow-self.dotsInScreen/2,dotNow+self.dotsInScreen/2)self.vline.set_xdata(dotNow)self.signal.freshLowerPlotPanLeftAndWidth.emit(frameNow-framesInScreen/2,frameNow+framesInScreen/2)self.canvas.draw()#實(shí)時(shí)更新波形defdrawInit(self,dataDict):self.clf()#print(22%250)self.media=dataDict['media']self.waveData=dataDict['data']self.framerate=dataDict['framerate']self.zipRate=int(self.secondsInScreen*self.framerate/self.dotsInScreen)self.plotDataList=[]self.getAllPlotData(self.zipRate)ifhasattr(self,'ax'):self.ax.clear()#print(22%250)self.ax=self.add_axes([0.1,0.1,0.8,0.8])self.ax.axhline(y=0,color='0.8',zorder=2)self.vline=self.ax.axvline(x=0,color='red',zorder=3)self.leftDot=0self.npSlice=[0]npSlice=np.arange(self.leftDot,self.leftDot+self.dotsInScreen)self.plotFunc(npSlice)self.mediaTimeChanged(0)#繪圖區(qū)初始化defplotFunc(self,npSlice):ifnpSlice[0]<0:Return#print(22%250)ifnpSlice[0]>self.waveDataLength:returnelifnpSlice[-1]>self.waveDataLength:npSlice=npSlice[0:self.waveDataLength-npSlice[0]]plotDataSliceDict=self.getSlicePlotData(npSlice)ymax=plotDataSliceDict['y_max']ymin=plotDataSliceDict['y_min']fillPlot=self.ax.fill_between(npSlice,ymax,y2=ymin,color='c',zorder=0)#print(22%250)self.plotDataList.append(fillPlot)#繪圖區(qū)屬性設(shè)置defclearAxes(self):length=len(self.plotDataList)iflength>2:foriinxrange(length-3):self.plotDataList[i].remove()self.plotDataList.pop(i)#清除坐標(biāo)defgetAllPlotData(self,zipRate):waveData=self.waveDataifisinstance(waveData,list):dataOne=waveData[0]dataTwo=waveData[1]dataLength=len(dataOne)chunksize=zipRate#print(22%250)numchunks=dataLength//chunksizeteam_1=dataOne[:chunksize*numchunks].reshape((-1,chunksize))team_2=dataTwo[:chunksize*numchunks].reshape((-1,chunksize))max_1=team_1.max(axis=1)max_2=team_2.max(axis=1)max_1_2=np.maximum(max_1,max_2)min_1=team_1.min(axis=1)min_2=team_2.min(axis=1)min_1_2=np.minimum(min_1,min_2)mean_1=team_1.mean(axis=1)mean_2=team_2.mean(axis=1)plotDataDict=dict(y_max=max_1_2,y_min=min_1_2,y_mean=mean_1,y_mean_2=mean_2)self.waveDataLength=numchunkselse:#print(22%250)dataLength=len(waveData)chunksize=zipRatenumchunks=dataLength//chunksizeteam_1=waveData[:chunksize*numchunks].reshape((-1,chunksize))max_1=team_1.max(axis=1)min_1=team_1.min(axis=1)mean_1=team_1.mean(axis=1)plotDataDict=dict(y_max=max_1,y_min=min_1,y_mean=mean_1)self.waveDataLength=numchunksself.plotDataAllDict=plotDataDict#獲取當(dāng)前繪圖區(qū)的全部數(shù)據(jù)defgetSlicePlotData(self,npSlice):ymaxSlice=self.plotDataAllDict['y_max'][npSlice]yminSlice=self.plotDataAllDict['y_min'][npSlice]ymeanSlice=self.plotDataAllDict['y_mean'][npSlice]ifself.plotDataAllDict.has_key('y_mean_2'):ymean2Slice=self.plotDataAllDict['y_mean_2'][npSlice]plotDataSliceDict=dict(y_max=ymaxSlice,y_min=yminSlice,y_mean=ymeanSlice,y_mean_2=ymean2Slice)else:#print(22%250)plotDataSliceDict=dict(y_max=ymaxSlice,y_min=yminSlice,y_mean=ymeanSlice)returnplotDataSliceDict#獲取當(dāng)前繪圖區(qū)的部分?jǐn)?shù)據(jù)defzoomIn(self):self.secondsInScreen/=2self.zipRate=int(self.secondsInScreen*self.framerate/self.dotsInScreen)ifself.zipRate==0:returnself.plotDataList=[]self.getAllPlotData(self.zipRate)self.currentTime_ms=self.media.currentTime()self.fresh()#print(22%250)#波形放大功能defzoomOut(self):self.secondsInScreen*=2self.zipRate=int(self.secondsInScreen*self.framerate/self.dotsInScreen)self.plotDataList=[]self.getAllPlotData(self.zipRate)self.currentTime_ms=self.media.currentTime()self.fresh()#波形縮小功能deftoNextScreen(self):print'next'self.currentTime_ms+=self.secondsInScreen*1000ifself.currentTime_ms>self.media.totalTime():self.currentTime_ms=self.media.totalTime()self.media.seek(self.currentTime_ms)#快進(jìn)功能deftoPreviousScreen(self):print'next'#print(22%250)self.currentTime_ms-=self.secondsInScreen*1000ifself.currentTime_ms<0:self.currentTime_ms=0self.media.seek(self.currentTime_ms)#快退功能classfreshSignal(QtCore.QObject):freshLowerPlotPanLeftAndWidth=QtCore.Signal(int,int)freshLowerPlotCurrentTime=QtCore.Signal(int)freshTimeNowLabel=QtCore.Signal(str)#print(22%250)freshMusicTotalTimeLabel=QtCore.Signal(str)freshVisionTimeLengthLabel=QtCore.Signal(str)freshScreenTime=QtCore.Signal(int)#創(chuàng)建信號(hào)defcontextMenuEvent(self,event):actionzoomIn=QtGui.QAction('xzoomIn',self)actionzoomOut=QtGui.QAction('xzoomOut',self)actionzoomIn.triggered.connect(self.zoomIn)actionzoomOut.triggered.connect(self.zoomOut)menu=QtGui.QMenu(self)#print(22%250)menu.addAction(actionzoomIn)menu.addAction(actionzoomOut)menu.addSeparator()menu.exec_(event.globalPos())#右鍵放大縮小功能圖5.2.2動(dòng)態(tài)波形區(qū)5.2.3上下波形區(qū)整合在上述內(nèi)容當(dāng)中已經(jīng)設(shè)置了動(dòng)態(tài)以及靜態(tài)波形等內(nèi)容,但是如果要真正實(shí)現(xiàn)波形的完整性,還需要進(jìn)行兩方面的充分整合,如下是具體的程序代碼和相關(guān)注釋內(nèi)容:classUpAndDownWaveWidget(QtGui.QWidget):def__init__(self,parent=None):super(UpAndDownWaveWidget,self).__init__(parent)self.setGeometry(100,100,1000,400)#設(shè)置幾何位置及長(zhǎng)寬self.upperPlotWidget=upperPlotWidget.plotControlWidget(self)#實(shí)例化plotControlWidget類(lèi)self.lowerPlotWidget=lowerPlotWidget.plotWidget(self)#實(shí)例化plotWidget類(lèi)self.path=None#print(22%250)self.media=Nonelayout=QtGui.QVBoxLayout()layout.addWidget(self.upperPlotWidget)#垂直添加upperPlotWidget波形區(qū)layout.addWidget(self.lowerPlotWidget)#垂直添加lowerPlotWidget波形區(qū)self.setLayout(layout)#print(22%250)self.upperPlotWidget.plotWidget.figure.signal.freshLowerPlotPanLeftAndWidth.connect\(self.lowerPlotWidget.figure.freshLeftAndWidthFromUpperPlot)#鏈接到freshLeftAndWidthFromUpperPlot信號(hào)self.upperPlotWidget.plotWidget.figure.signal.freshLowerPlotCurrentTime.connect\(self.lowerPlotWidget.figure.freshCurrentTimeFromUpperPlot)#鏈接到freshCurrentTimeFromUpperPlot信號(hào)defsetMedia(self,media):self.media=media#print(22%250)defanalyzeWaveAndDrawInit(self):path=str(self.media.currentSource().url().path())path=path[1:]form=waveForm.waveform(path)waveData=form.getWaveData()dataDict=dict(data=waveData,#print(22%250)framerate=form.framerate,media=self.media)self.lowerPlotWidget.figure.drawInit(waveData)self.upperPlotWidget.plotWidget.figure.drawInit(dataDict)#解析波形并初始化圖5.2.3上下波形區(qū)整合第6章系統(tǒng)整合與測(cè)試6.1程序主界面整合對(duì)于音頻進(jìn)行解析以及對(duì)于波形進(jìn)行繪制之后,還需要對(duì)于所有的程序進(jìn)行有效整合。具體的代碼和注釋?zhuān)篶lassWaveWidget(QtGui.QWidget):def__init__(self,parent=None):QtGui.QWidget.__init__(self,parent)self.ui=Ui_widget_waveModule()#實(shí)例化Ui_widget_waveModule類(lèi)self.ui.setupUi(self)#調(diào)用setupUi函數(shù)player=Player(self)#實(shí)例化Player類(lèi)self.ui.horizontalLayout_musicToolBox.addWidget(player)#添加音頻模塊upAndDownWaveWidget=UpAndDownWaveWidget(self)#實(shí)例化UpAndDownWaveWidget函數(shù)self.upAndDownWaveWidget=upAndDownWaveWidgetself.ui.horizontalLayout_plots.addWidget(upAndDownWaveWidget)#添加波形模塊upAndDownWaveWidget.setMedia(player.getPlayerMedia())#將波形與音頻同步player.signal.fileChoosedSignal.connect(upAndDownWaveWidget.analyzeWaveAndDrawInit)#鏈接到文件選擇功能player.signal.TimeNowChanged.connect\(upAndDownWaveWidget.upperPlotWidget.plotWidget.figure.mediaTimeChanged)#鏈接到時(shí)間選擇功能player.ui.pushButton_goLeft.clicked.connect(upAndDownWaveWidget.upperPlotWidget.plotWidget.figure.toPreviousScreen)#鏈接到快退功能player.ui
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 泄洪閘 施工方案
- 中國(guó)古代軍事思想-深度研究
- 智能制造技術(shù)探索-深度研究
- 螺栓油漆施工方案
- 數(shù)據(jù)驅(qū)動(dòng)決策模型-深度研究
- 企業(yè)財(cái)務(wù)風(fēng)險(xiǎn)管理-第7篇-深度研究
- 智能化數(shù)據(jù)治理-深度研究
- 專(zhuān)注力提升技術(shù)在移動(dòng)應(yīng)用中的實(shí)踐-深度研究
- 康復(fù)工程與康復(fù)醫(yī)學(xué)-深度研究
- 智能研發(fā)項(xiàng)目管理-深度研究
- 2024版塑料購(gòu)銷(xiāo)合同范本買(mǎi)賣(mài)
- JJF 2184-2025電子計(jì)價(jià)秤型式評(píng)價(jià)大綱(試行)
- GB/T 44890-2024行政許可工作規(guī)范
- 2024年安徽省中考數(shù)學(xué)試卷含答案
- 2025屆山東省德州市物理高三第一學(xué)期期末調(diào)研模擬試題含解析
- 2024年滬教版一年級(jí)上學(xué)期語(yǔ)文期末復(fù)習(xí)習(xí)題
- 兩人退股協(xié)議書(shū)范文合伙人簽字
- 2024版【人教精通版】小學(xué)英語(yǔ)六年級(jí)下冊(cè)全冊(cè)教案
- 汽車(chē)噴漆勞務(wù)外包合同范本
- 2024年重慶南開(kāi)(融僑)中學(xué)中考三模英語(yǔ)試題含答案
- 2023年最新的校長(zhǎng)給教師春節(jié)祝福語(yǔ)
評(píng)論
0/150
提交評(píng)論