結束了朝七晚十二的生活後,最近幾天好好放縱了一下,把庫存裡的還沒玩的遊戲都玩完或者玩到卡關,把想再看一遍的書又看了一遍,奢侈地睡了個覺。但是看了看開學時間不斷地逼近,計劃卻隻完成了那麼幾個,心裡着實不甘。于是又來敲鍵盤了。
Tzvi講過,我們Matlab隻學一個學期的基礎,後面因為不同人的發展方向不同,是以隻能靠學習基礎的方式自行學習你需要用到的内容。是以今天要摸的是Matlab裡有關于sound的内容(Matlab的功能真的很雜,它甚至還有FM Broadcast Receiver)
《Mastering MATLAB》裡關于SOUND的介紹非常少,隻有短短兩頁内容,可見在Matlab裡,sound并不是什麼主要内容或者說是弱項。sound在matlab裡更多的并不是用于制作音樂,而是提醒和分析聲音背後的數學,實體規律
為什麼說是提醒呢,因為有些比較複雜的程式,往往需要matlab運算很久才會有結果,這時候人一般是不會盯着螢幕等着出結果,而是走開先去幹其他事。這時候就需要matlab在運算完後發出提示,最好是聲音。是以sound在matlab裡更多是用于提醒程式已運作完,結果已得出(一般用beep函數)。不過也有人用warndlg(彈出視窗)來提醒
在《Mastering MATLAB》裡這部分内容,似乎把函數分成了high-level functions (audioplayer, audiorecorder, getaudiodata, audiodevinfo...) 和 lower-level functions (sound, soundsc, auread, wavread, auwrite, lin2mu...)。但我覺得分高低級并沒有什麼用
還是從頭開始嘗試,就從怎麼播放系統自帶的音頻開始吧
其實matlab自帶了很多聲音,除了我們剛剛在上面提到的我們用matlab經常能聽到的beep之外,還有chirp(叽叽喳喳的鳥叫聲), gong(銅鼓), handel(哈雷路亞), laughter, splat(東西掉下來的啪嗒聲), train。這些東西都是mat檔案,位置在
"MATLAB/R2018b/toolbox/matlab/audiovideo"

我們可以通過以下函數來播放
load chirp; %讀取chirp.mat檔案
sound(y,Fs); %播放以y為樣本,Fs為頻率的聲音
還可以這麼寫
load train;
player = audioplayer(y,Fs); %建立用于播放音頻的對象
play(player);
load我們應該都能看懂,就是讀取檔案,而mat檔案就是matlab自帶的資料封包件格式。sound(y,fs)就是播放以y為樣本,fs為采樣頻率的聲音;與之相對的是play,它可以從 audioplayer 對象播放音頻。audioplayer就是建立用于播放音頻的對象
audioplayer對象長這樣
其中fs采樣頻率以Hz為機關,指的是采所有的樣本,但是一秒内采fs個樣本。必須有震動,即變化,或者說是波才能形成聲音,是以當樣本全為同一個值的時候,不管這個值有多大,它都是沒有聲音的,隻有在值出現變化的時候,才會有聲音
嗯嗯,你們動手試試吧,這些聲音都挺有趣的
然後我們看回我剛剛放的第一張圖,裡面箭頭的是系統自帶的包含音頻資訊的mat檔案,方形的是敲琴視訊,還有圓圈圈出來的是matlab的一個彩蛋。比較神奇的是,唯獨這個mat檔案的頻率Fs(7418)和其他mat的頻率(8192)不一樣,而且其他的樣本資料名字都是y,唯獨它是叫mtlb。有興趣的朋友可以自己去試試這個彩蛋
我們現在看到的都是已經從音頻檔案轉為mat的檔案了,那如果我們自己要轉換怎麼做呢?這時候就需要audioread函數了
首先要把你要轉換的音頻檔案放在目前目錄裡,目前目錄你可以用pwd函數,看看是在哪裡,或者直接看上面
比如我把一個叫night.mp3的檔案,放在目前目錄,然後就可以使用函數了
[y,fs] = audioread('night.mp3'); %讀取音頻檔案,并輸出到工作區的"y","fs"
sound(y,fs);
這時候我們發現,工作區出現了"fs","y"這兩個資料,同時電腦還緩緩播放出好聽的音樂。這裡的"fs"就是這個音頻的頻率,"y"就是音頻資料,而且"y"還是一個nx2的double,為什麼是2呢,因為現在大多數音頻檔案都是雙聲道了啊。再補充一點,還有一個函數叫做soundsc,它可以縮放音頻信号 y 的值以使其位于 –1.0 到 1.0 範圍内,盡可能提高音頻的音量,而不用裁剪
然後我們就可以點右上角的小三角形,對工作區進行儲存
現在我們可以把原來的mp3檔案和新的mat檔案進行對比,就可以發現,這麼做是非常的不劃算的,檔案大小一下子大了21倍。畢竟mat不是專門用來儲存音頻資訊的,情有可原
沒什麼卵用不要緊,主要是這樣可以裝逼,不是嗎。找個好友,發給已經轉化過音頻的mat檔案給ta。"你下載下傳這個檔案後,打開matlab,把這個mat檔案放在目前目錄,然後在指令視窗輸入以下代碼:"
load night;
sound(y,fs);
看到這麼大的檔案,這麼簡潔的代碼,不會讓人覺得一頭霧水的很厲害嗎,就是沒什麼用而已,還不如直接聽mp3
想要逼格再高一點,就把它做成剛剛講的audioplayer對象,這樣連樣本資料也看不見了
SampleRate就是它的采樣頻率,相當于"fs",數值越高就相當于波被壓縮了一樣,聲調變高,時間變短。說到了變速和變調,我們順便也提提"變速不變調"和"變調不變速"兩種。變速不變調,需要你把樣本資料值壓縮成二分之一,然後用2*fs的采樣頻率播放。而變調不變速,需要你把樣本長度增長一倍,然後用2*fs的采樣頻率播放。
BitsPerSample就是它的比特率,聲音中的比特率是指将模拟聲音信号轉換成數字聲音信号後,機關時間内的二進制資料量,是間接衡量音頻品質的一個名額
NumberOfChannels就是它的頻道數,相當于我們"y"的column值。TotalSamples就是我們現有樣本總數,相當于"y"的row值
剛剛也說明了,play播放的是audioplayer對象;sound播放的是以fs為頻率,y為樣本的聲音。再細點講,audioplayer相對于直接使用sound,可操作的地方多很多
比如說你播放sound,想要停的話,你就輸入
clear sound;
不過你也隻能停止sound的播放,而對于audioplayer你可以play(播放),pause(暫停),resume(繼續播放),stop(停止),還有get, set(設定屬性), isplaying, playblocking等,格式寫成
play(playerObj);
pause(playerObj);
resume(playerObj);
stop(playerObj);
... ...
playerObj填入audioplayer對象的名稱
另外,play還可以截取audioplayer對象的部分進行播放,格式為
play(playerObj,start);
或
play(playerObj,[start,stop]);
裡面的start或stop應該如此指派
start = playerObj.SampleRate * 4;
這個意思是start是playerObj的從前往後數的第四秒。因為想要取我們要的這個位置的值,除了和時間,還和播放它的采樣頻率有關,兩者乘起來才是我們要的開始樣本資料的值。就好比我們要接這麼多的水,除了和接水的時間有關,還和開水龍頭的大小有關
此外,我們可以看見audioplayer對象下面包含了許許多多的資料,我們想要單獨使用某個值的時候,格式就是"對象名.子資料名"。比如我們要取我們剛剛建立的名為"player"的audioplayer對象裡的"BitsPerSample"就寫作"player.BitsPerSample"
把這個整合起來就是這麼寫
load handel.mat;
player = audioplayer(y,Fs);
start = player.SampleRate * 4;
play(player,start);
我們可以發現,handel這個音頻從第四秒(start)開始播放。stop也是一樣的道理
另外play是可以一次性播放許許多多個音頻的,沒有排他性,這樣會聽起來很嘈雜(sound也沒有排他性)。用playblocking替代play就可以解決這個問題,這是一個具有排他性的函數,即它會播放一個音頻完後再播放下一個
能播就能錄,這時候用的函數是audiorecorder,這個函數可以建立用于錄音的對象,格式為
recorder = audiorecorder
或
recorder = audiorecorder(Fs,nBits,nChannels)
Fs為以Hz為機關的采樣率,MATLAB 的硬性限制為 1000 Hz <= Fs <= 384000 Hz,預設: 8000。nBits為采樣位數,預設: 8。nChannels為通道數:1(單聲道)或 2(立體聲),預設: 1
Matlab說明文檔的示例如下
% Record your voice for 5 seconds.
recObj = audiorecorder; %建立audiorecorder對象
disp('Start speaking.')
recordblocking(recObj, 5); %排他性地單獨對recObj這個對象錄5s的音
disp('End of Recording.');
% Play back the recording.
play(recObj); %播放recObj
% Store data in double-precision array.
myRecording = getaudiodata(recObj); %将recObj導出為資料并指派給myRecording
% Plot the waveform.
plot(myRecording); %畫myRecording的圖像
這個例子特别好,比較全面。講了建立,錄音,轉為資料,畫圖幾個方面。這裡面的recordblocking也可以用record代替。也就是說,audioplayer - play - playblocking三者的關系和audiorecorder - record - recordblocking三者的關系類似。然後我就随便瞎哼哼,導出了個圖像(這段我錄了10s,但是已經有80000個資料。)
可以播可以錄,也就可以儲存了,使用函數audiowrite,格式為
audiowrite(filename,y,Fs)
這裡filename的格式可以寫為這麼幾種
'myFile.m4a'
'../myFile.m4a'
'C:\temp\myFile.m4a'
比如說儲存我們剛剛的錄音為wav檔案
audiowrite('mysound.wav',myRecording,8000);
%這裡的8000就是recObj.SampleRate
然後你就可以在你的檔案夾裡看見你導出的wav檔案了
它支援的格式和通道數有
還有一個函數叫做audioinfo,它可以幫你檢視有關于audio的資訊,比如
info = audiodevinfo
還可以這麼寫
audioinfo('mysound.wav')
不知道你是否知道Mu-Law
μ-law(或Mu-Law)作為一種壓縮擴充的方法,μ-law可以改善信噪比率而不需要增添更多的資料。
均勻量化時 ,由于對編碼範圍内小信号或大信号都采用等量化級進行量化 ,是以小信号的“信号與量化噪聲比”小 ,而大信号的“信号與量化噪聲比”大 ,這對小信号來說是不利的。為了提高小信号的信噪比 ,可以将量化級再細分些 ,這時大信号的信噪比也同樣提高 ,但這樣做的結果使數位率也随之提高 ,将要求用頻帶更寬的信道來傳輸。采用壓縮的量化特性是改善小信号信噪比的一種有效方法。它的基本思想是在均勻量化前先讓信号經過一次處理 ,對大信号進行壓縮而對小信号進行較大的放大。由于小信号的幅度得到較大的放大 ,進而使小信号的信噪比大為改善。
信噪比,英文名稱叫做SNR或S/N(SIGNAL-NOISE RATIO),又稱為訊噪比。是指一個電子裝置或者電子系統中信号與噪聲的比例。這裡面的信号指的是來自裝置外部需要通過這台裝置進行處理的電子信号,噪聲是指經過該裝置後産生的原信号中并不存在的無規則的額外信号(或資訊),并且該種信号并不随原信号的變化而變化。
同樣是“原信号不存在”還有一種東西叫“失真”,失真和噪聲實際上有一定關系,二者的不同是失真是有規律的,而噪聲則是無規律的。
——百度百科
部分相關内容,你還可以通過下面這個視訊進行了解
【作死實體小講堂】高音質的音頻是如何錄制的 音頻增益與降噪的原理 @FPS羅茲 靈魂字幕
https://www.bilibili.com/video/av16759300
Matlab就有這麼一個函數可以将linear audio轉化為mu-law,叫lin2mu,相反則用mu2lin。mu = lin2mu(y) 将範圍 -1 ≤ Y ≤ 1 内的線性音頻信号振幅轉換為範圍 0 ≤ u ≤ 255 内的 mu-law 編碼"flints"
Matlab不能直接打開mp3,wma等我們經常會用到的音頻檔案格式,但是在《Mastering MATLAB》有提到以下内容
Two industry-standard sound file formats are supported in MATLAB. NeXT/Sun audio format (file.au) files and Microsoft WAVE format (file.wav) files can be written and read.
——《Mastering MATLAB》
那個au格式不講,我沒見過,不過使用方式和wav很像。與wave相關的函數有四個,分别是:
wavplay Plays WAVE format sound file (depreciated; use audioplayer instead)
wavrecord Records sound using audio input device ( depreciated; use audiorecorder instead)
wavread Reads WAVE format sound file
wavwrite Writes WAVE format sound file
——《Mastering MATLAB》
又是不建議使用的函數,在MATLAB Release Notes裡也指出來了這幾個函數不建議使用
——R2014a - Data Import and Export - Functionality being removed or changed
這些函數很早就不建議使用了,從13到15幾個版本的Release Notes連續提出警告,然後你在matlab文檔裡也找不到這幾個函數的具體介紹文檔,應該是不可以使用了。我看了一下《Mastering MATLAB》的發行時間,2012,哦,好吧
但是!但是我卻在百度文庫看到一篇挺新的文章還在用這幾個函數
我有點好奇,畢竟可能隻是提醒不建議,而不是完全不能用了。是以我自己打了代碼試試看。這紅線?看來不行。運作了,果然不行(這裡我的換行打錯了,得fprintf才能用\n)
好了,說了這麼多,除了錄音之外,基本上都是現有的東西,那可不可以自己做呢?比如編輯音樂?有是有,雖然不如專用的MuseScore或者GarageBand等好用
這部分内容需要很多比較基礎的樂理知識,其中也包含了不少數學和實體的美妙,有興趣的朋友可以去了解了解
我知道的,寫得比較好,比較全的有下面幾個
十二平均律理論的科學依據是什麼?
https://www.zhihu.com/question/27345554
寫給理工科人看的樂理(四)和弦與調式
http://www.cnblogs.com/devymex/p/3386886.html
純律、五度相生律和十二平均律有何關系?
https://www.zhihu.com/question/20612595
如何通俗易懂地解釋八度與十二平均律?
https://www.zhihu.com/question/22822711
聽聽函數,看看聲音--Matlab的sound()函數
https://blog.csdn.net/weaponsun/article/details/46695255
黑白鍵的故事 | 混亂博物館
https://zhuanlan.zhihu.com/p/37546103?utm_source=wechat_session&utm_medium=social&utm_oi=863156048981295104
(感謝kj同學的推薦)
音高和頻率轉換表
https://wenku.baidu.com/view/ed84865e1711cc7931b716bc.html
使用matlab進行簡單音樂合成
https://wenku.baidu.com/view/1a4428010740be1e650e9a4d.html
我們可以看到,聲音的音高跟它的頻率有關,它們之間符合以下公式關系
其中p為MIDI number(亦可以了解為音高),f為頻率(Hz)。一般定鋼琴上小字一組的la(a1)為标準音,p=69,f=440。這樣推算過來,中央C(do c1)的p=60,f=261.63
http://newt.phys.unsw.edu.au/jw/notes.html
我沒看懂這個圖的note name在寫什麼,因為一般我們都是下圖這麼标的
baby.bao-jian.net
還有我不太明白他這個p是怎麼定義的,是以我看到有人拿鋼琴鍵當做p寫進公式的時候,我對照着标準公式看了很久,才知道ta寫的不是标準公式,而是把p換做鋼琴鍵數(好吧,它有寫很清楚,隻是我比較蠢)
上面的問題用下圖可能比較好了解
https://blog.csdn.net/weaponsun/article/details/46695255
fs=44100;
t=0: 1/fs: 0.5; %因為采樣頻率為fs,是以我們要提供的資料的間距為1/fs
do=sin(2*pi*261.63 *t);
re=sin(2*pi*293.66 *t);
mi=sin(2*pi*329.63 *t);
fa=sin(2*pi*349.23 *t);
so=sin(2*pi*392.00 *t);
la=sin(2*pi*440.00 *t);
ti=sin(2*pi*493.88 *t);
Cscale=[do,re,mi,fa,so,la,ti];
sound(Cscale,fs)
——聽聽函數,看看聲音
--Matlab的sound()函數
我們可以發現這段音樂失真的很嚴重,需要修正。這是因為而我們一般聽到的聲音都有始有終,從小到大,再從大到小,不會一下子就最大聲。簡單來說,這裡失真就是因為發聲瞬間數值的內插補點太大了,即相位不連續,産生高頻分量。這裡的每一個聲音都是從頭到尾都是同一個振幅,我們需要通過一個修正振幅來調整它們,比如說這裡的修正振幅就可以寫作
mod = sin(pi*t/t(end)); % Modification function
使其每一個音都是一個小山丘的發聲形式,就跟我們彈鋼琴一樣,敲下按鍵的那一瞬間,聲音變大,手指離開按鍵的時候,聲音變小,而按到底的時候聲音最大。這些整合起來如下
fs = 44100;
t = 0:1/fs:0.5;
mod = sin(pi*t/t(end));
do = mod .* sin(2*pi*261.63 *t);
re = mod .* sin(2*pi*293.66 *t);
mi = mod .* sin(2*pi*329.63 *t);
fa = mod .* sin(2*pi*349.23 *t);
so = mod .* sin(2*pi*392.00 *t);
la = mod .* sin(2*pi*440.00 *t);
ti = mod .* sin(2*pi*493.88 *t);
Cscale=[do,re,mi,fa,so,la,ti];
sound(Cscale,fs);
你再運作試試看,是不是就沒有了"塔塔塔"的破音
還有一種調幅的方式叫做包絡函數
mod = (t.^4).*exp(-30*(t.^0.5));
mod = mod*(1/max(mod));
詳情請看
matlab演奏最炫民族風的代碼求翻譯,越詳細越好,真心看不懂?
https://www.zhihu.com/question/20248007
我們除了可以用各個音高的頻率來表示聲音,還可以通過五度相生律來推每個音。詳細内容請看上面的"黑白鍵的故事"那個連結
http://blog.csdn.net/bat67
很多采樣頻率fs都是44100Hz,這是因為這個是理論上CD音質的界限(據說是通過"乃奎斯特取樣定理"標明的),而最先很多mp3都是從CD拷來,是以我們會有很多音頻檔案的采樣頻率都是44100Hz。而高于48KHz的采樣率,人耳分辨不出來,也就沒多大用處了。但是我還是不明白matlab預設的采樣頻率8192是怎麼來的
另外還需提前提出來的是,現在你去看别人用matlab編寫的音樂,它們的十六分音符時長都為0.125s
這是因為它們曲子的BPM(Beat Per Minute,拍子數,每分鐘節拍數的機關。一般琴譜左上角一個四分音符等于某個數值指的就是BPM)都為120,即一分鐘有120拍,四分音符為一拍,是以一拍0.5s,而十六分音符就是0.125s
zhidao.baidu.com
是以我們可以總結一下,一般在matlab裡制作編寫音樂的流程如下
1.定義采樣頻率
fs = 44100;
dt = 1/fs; %每個采樣點的時間差
2.定義BPM(挺多程式定義的是十六音符,然後通過十六分音符推出其他音符)
T16 = 0.125;
t16 = 0:dt:T16; %每個采樣點的時間點
[~ k] = size(t16);
%我們想知道十六音符的采樣個數,這個會在後面設定休止符的時候用到。因為沒必要知道第一個元素的數值,是以我們可以直接用"~"代替。不過這裡也可以寫成"k = size(t16,2);"
t4 = linspace(0,4*T16,4*k);
%這個是由十六分音符推四分音符。linspace可以生成線性間距向量,y = linspace(x1,x2,n) 生成 n 個點。這些點的間距為 (x2-x1)/(n-1)。
[~ i] = size(t4);
... ...
3.定義每個音,要分音高和時長
(上面已經給出直接用頻率寫的音符,和用五度相生律推的音符兩種方法)
4.定義休止符和整合旋律
5.如果有多個旋律,要把這些旋律的資料加起來,然後歸一化,防止失真
比如說你有旋律m1, m2, m3,你需要
y = m1+m2+m3;
y = y/max(y);
%歸一化,壓縮數值,使之最大值的絕對值為"1",防止失真。這個主要還是因為sound(y,fs)裡的y要求是-1到1之間的數值。不過這個問題也可以用soundsc函數解決
6.播放
sound(y,fs);
了解完這些後,我們就可以開始着手編寫自己的音樂了
《那些年,我們一起彈的鋼琴曲》
我們可以看到,這個曲子的BPM是100,而不是120。是以一拍就是0.6s而不是0.5s了
這段播放出來就是開頭的那個語音。想要我制作《一生有你》的編曲m檔案的朋友,可以在我的公衆号背景發送"一生有你"
matlab裡,sound的相關内容還有許許多多可以講的東西。有興趣的話,還可以看看别人怎麼做随機音樂
[實習] 用matlab生成随機序列音樂
https://www.douban.com/group/topic/12214892/
另外為了感謝能夠從頭看到尾的朋友,我決定送上點福利,去Numerical computing with functions 這個官網上免費下載下傳,或者在網址那裡輸入
https://link.zhihu.com/?target=https%3A//github.com/chebfun/chebfun/archive/master.zip
下載下傳完後,把檔案解壓,打開解壓的檔案(變為目前目錄)就開始開心的耍了。在指令視窗分别輸入以下三個代碼,在matlab上玩三種貪吃蛇
chebsnake
chebsnake('equi')
chebsnake2
寫一篇推文不容易,希望大家觀看,收藏,投币三連(doge),謝謝!