前言:
周末了給大家整點有趣的東西吧,在不借助電腦聲卡的情況下,只利用電腦主板上的蜂鳴器,就能讓電腦自己哼起歌來,感覺還挺好玩的呢~
廢話不多說,讓我們愉快地開始吧~
開發工具
Python版本:3.6.4
相關模塊:
PyQt5模塊;
以及一些python自帶的模塊。
環境搭建
安裝python並添加到環境變量,pip安裝需要的相關模塊即可。
原理簡介
原理其實挺簡單的,主要就是利用python來控制電腦主板上的蜂鳴器以不同的頻率發出聲音從而模擬人哼歌時的效果~
具體而言,我們小學就學過,聲音是由物體震動產生的,它包括以下幾個部分:
1. 音調: 聲音的高低,由發聲體的振動頻率決定,頻率越高,音調越高;
2. 響度: 人耳感覺到的聲音的大小,它跟發聲體的振幅有關.振幅越大,響度越大;振幅越小,響度越小;
3. 音色: 發聲體的聲音品質,由發聲體本身的特征決定.是區別聲音的重要標志.
這是考點,麻煩還在念初中的粉絲記一下,考試要考的,別一到周末了就只玩手機不學習~
對於電腦主板上的蜂鳴器來說,音色和響度基本上已經確定沒法改了,所以我們只能在頻率上動腦筋,從而讓蜂鳴器哼出我們想要聽的歌來~
具體而言,我們可以調用這個函數來讓蜂鳴器哼歌:
1 import ctypes
2 beep_player = ctypes.windll.kernel32
3 beep_player.Beep(freq, beats)
其中freq代表頻率,beats代表節拍(就是當前音符播放的時長)。好的,看到這里可能有人懵了,別急,讓我來舉個例子說明我們到底應該怎么做。
首先,我們去網上找一首喜歡的歌的音樂簡譜,這里以小幸運為例:
可以發現簡譜上有數字1234567這7個基本音符,唱作:
1 1: do
2 2: re
3 3: mi
4 4: fa
5 5: sol
6 6: la
7 7: si
每個基本音符代表聲音的一個頻率,在基本音符上方標記"·"時,則代表該音升高一個八度,稱為高音,反之則代表該音降低一個八度,稱為低音(這里就不考慮倍高音和倍低音的情況了):
一般而言,我們可以假設高音do的頻率是do的兩倍,是低音do的四倍,其他音符類似。再根據十二平均律:
1 一種音樂的定律方法,將一個八度平均分成十二等份,
2 每等分稱為半音,是最主要的調音法。
3 音高八度音指的是頻率加倍(即二倍頻率)。
4 八度音的頻率分為十二等分,即是分為十二項的等比數列,
5 也就是每個音的頻率為前一個音的2的12次方根:
6 其近似值約為2^(1/12) = 1.06
我們只需要知道do的頻率,就可以推算出其他音符的頻率了(比如do的頻率是1,那么re的頻率就是11.061.06)。一般而言,do的頻率和簡譜中的調號的對應關系如下:
1 'C': 523,
2 'D': 587,
3 'E': 659,
4 'F': 698,
5 'G': 784,
6 'A': 880,
7 'B': 988
ok,至此,我們搞定了freq,現在再來看beats。在簡譜中,一般通過加"·"和短橫線"-"來表示音的長短:
1 1. 在基本音符右側加記一條短橫線, 表示增長一個四分音符的時值
(就是這個音的長度*2)
2 2. 在基本音符下方加記一條短橫線, 表示縮短原音符時值的一半
3 3. 音符X右側加·時代表增長原音符時值的一半
4 4. 在簡譜中, 大於四分音符的單純音符通常不加記·,即用X--來表示X-·
盜個圖更直觀一點說明吧:
OK,如此一來,我們就可以很輕松地確定上面的音樂簡譜中每個音符的freq和beats,從而調用函數讓蜂鳴器哼出這個音符來了,所以音符連起來哼不就等於讓蜂鳴器哼歌了嘛~
為了方便程序確定每個音符的freq和beats,我們把簡譜重寫一下,就像這樣:
即每個音符由三個元素組成:
[基本音符][低音/中音/高音][音的長度]
然后寫過函數解析一下:
1 '''解析'''
2 def parse(self, filepath):
3 song_info = open(filepath, 'r').read().replace('\n', '').split(',')
4 tone = song_info[0]
5 song_info = song_info[1:]
6 return tone, song_info
並根據解析結果播放就ok啦:
1 '''播放'''
2 def play(self):
3 filepath = self.musicfilepath_edit.text()
4 if not os.path.isfile(filepath):
5 return
6 tone, song_info = self.parse(filepath)
7 do = self.tone2freq_dict[tone]
8 re = int(do * self.tone_scale * self.tone_scale)
9 mi = int(re * self.tone_scale * self.tone_scale)
10 fa = int(mi * self.tone_scale * self.tone_scale)
11 sol = int(fa * self.tone_scale * self.tone_scale)
12 la = int(sol * self.tone_scale * self.tone_scale)
13 si = int(la * self.tone_scale * self.tone_scale)
14 notes = [0, do, re, mi, fa, sol, la, si]
15 for item in song_info:
16 if notes[int(item[0])] == 0:
17 time.sleep(self.beats / 1000)
18 else:
19 self.beep_player.Beep(int(notes[int(item[0])]*self.pitchs_dict[item[1]]), int(self.beats * float(item[2:])))
文章到這里就結束了,感謝你的觀看,關注我每天分享Python小工具系列,下篇文章根據中文姓名猜測對方性別