使用Sencha Architect 2快速搞定Web App的UI

Ext JS是啥
首先簡單介紹一下Ext JS好了。不知道大家有沒有用過miroko?他是N年前我跟水利系室友非常愛用的免費服務,可以幫你掛BT並存到他所提供的網路硬碟空間內,對學術網路頻寬超級大,一秒可以衝到5~10Mb。(但是自從開始收費就跟它再會了) 它那種淡藍色UI,就是使用當時剛推出的Ext JS 1.0刻的。還是沒啥畫面嗎?這裡有真相

進入正題前,先看看官方提供的範例長怎樣吧!

feed1
圖:官方的範例之一:Feed Viewer,阿就藍藍的,非常的『2007』

簡而言之,Ext JS是Sencha公司推出的一個純JS的Web前端框架,提供一般Web App會用到的UI元件(按鈕、表格、Tab…)讓你實作出想要的user flow;且便於繼承擴充,定義出自己客製的元件;另外也提供許多好用的JS utility及Ajax Data Source支援,跟後端CRUD做完美的配合。在外觀上,預設主題是簡單但有點過時的淡藍色,不過他的主題是以SASS/Compass實作,因此只要找對美工,也是可以盡情揮灑的。目前它大多應用於企業端的內部Web Application based的資訊系統(至少敝公司將它視為UI標準之一orz,另外不知道為啥,在大陸跟日本的開發者社群似乎都相當發達)。我個人認為它的優點在於良好的繼承架構、便於快速開發及擴充,還有完整豐富的社群、官方支援及API(用商業化套件的好處就在於任何奇怪、無恥的問題只要PO個版就有解,瀏覽器相容等問題都不用自己去搞,也不會叫你RTFM);但是相對的,跟jQuery+jQuery UI的方便性比起來,它的缺點是架構較為固定,很難去把它的架構翻掉自己重新設計;另外最重要的,它在某些情況可能要錢
kitchensink1
圖:Ext JS 4.1 提供的Nepune主題

授權
其實寫這篇文章真的有點掙扎,因為真的像是業配文orz。還是先來講講授權的部分:Ext Core是Ext JS的核心,提供類似於jQuery的DOM操作等功能,是免費的且使用MIT License;打個比方:Ext Core之於Ext JS,就如同jQuery之於jQuery UI。雖然Ext JS也算是開源的,但它的授權就比較複雜。如果也是用於open source開發,則適用GPLv3;如果是商業用途且將原始碼視為公司proprietary,則適用Sencha Commercial License;如果是要把它做成另外的商業化SDK(如Ext.NET),Sencha也提供OEM License。而今天要講的Sencha Architect,則是Sencha推出的架構設計工具,一套要價$399鎂,但提供免費試用。

開始使用Sencha Architect做第一個Ext JS的UI
進入正題,前幾天Sencha發表了最新的Sencha Architect 2 (梗在這,因為它以前叫Ext Designer,現在升級變Architect XD)。它是一個強大的東西,只要拉一拉、摳一摳,十分鐘就可以把UI刻好了。除了拉UI之外,它之所以會改名為Architect,是因為它可以直接在裡面寫code、做event handling、甚至定義MVC架構。(另外一大賣點是可以開發Sencha Touch當成手機App,但是本周主題是Web App,所以就不提這段XD)這篇文也不會涉獵到太深的架構部分,目標先設定在快速上手並做出一個會動的Web UI。話不多說,讓我們開始吧(羞)

下載並安裝
載點在此,試用前須註冊Sencha Forum的帳號。它本身是以QT及其內建Webkit寫成的跨平台程式,可以在Windows/MacOS/Linux上執行。將程式打開之後,可以看到一個很熟悉的WYSIWYG所見及所得編輯器:左邊是工具箱、中間是畫布、右上是階層圖、右下是一欄欄的屬性。
wysiwyg1
圖:Sencha Architect跑起來的樣子

開始拉UI
迫不及待要從左邊拉東西進來了吧?首先,身為一個web app,會需要的是一個viewport。它可以把整個網頁的畫面撐開,讓我們在裡面做layout。
viewport6
圖:把整個Web App畫面撐開的東西是Viewport

繼續瘋狂拉東西進來之前,還是要先對Ext JS所提供的各種layout有基本的認識。這個Ext Layout Browser裡面有各種layout的DEMO及基本介紹。一般來說,我們常常在web app的最外面使用Border Layout,將畫面分成東南西北中發板幾塊(region)。
要設定這個viewport的layout類型,可以在右邊屬性中找到layout下拉選取,或是在畫布上的藍色齒輪跳出的快速設定popup中選取。接下來真的就可以從左邊亂拉元件了。要注意的是,若是在一個border layout的container裡面,它需要有一個region: ‘center’ (中央)的子元件;其他東西南北則不一定要有。拉完之後可能長這樣
region6
圖:Border Layout的示意圖,紅色框起來的地方套用了border layout

以下面的圖為例,我西邊放了一個Tree Panel,將它的collapsible(可收合)及split(邊緣分割線)屬性設為true;中間則放了一個包含三個tab的Tab Panel。在第一個Tab,我將它的layout設為absolute,這時候畫面上會出現格線方便我們直接拖拉調整子元件的位置。若要將表單欄位貼到最右邊,可以將anchor屬性設為100%。
在我們拉表單的時候,可以在畫布上的元件按右鍵使用duplicate功能快速複製;複製後可用transform將其轉為其他類別的元件(如:將combo box下拉選單欄位轉為date field日期欄位。它們都是繼承Ext.form.field.Base)。

看看內建的API文件
Sencha Architect的一大優點就是它本身整合了Ext的documentation,大幅減少了設計時翻文件的痛苦。如下圖,在左邊的工具箱中點每個元件後,下方都會出現簡單說明;另外,在屬性視窗中的每個屬性旁都有一個問號,滑鼠移上去也會秀出簡單說明。若是想看完整的document,也可以點連結直接跳到線上API去看。
api1
圖:Sencha Architect中內建的documentation功能

看看很好很強大的線上API文件吧!
Ext的原始碼本身是以JS Doc形式做self-documentation的。Sencha也開發了一個工具叫JS Duck將原始碼直接變成像這樣的API網站。裡面可以看到它提供所有的功能,元件Class的繼承hierarchy,還有範例以及別人的評論。這裡面真的很值得探索!

事件處理
若是我想讓user按按鈕之後,將左邊的tree收起來,該怎麼做?(例子很爛請包涵XD) 首先我們先將左邊的tree panel取一個ID叫myTreePanel。有了ID之後,在任何地方都可以使用Ext.getCmp(‘元件ID’)來取得該元件,並進行操作。(題外話,當然這不是唯一方法。若是熟悉CSS selector,也可以用類似jQuery的方法來取得元件,如query、up、down等等。這種寫法相當適合controller使用。)
id6
圖:給咱們Tree panel一個ID

接下來,在button的屬性視窗中加入一個event handler如下圖。一個按鈕所有可能觸發的event全部在下拉選單列給我們看了!很直覺地,click應該就是我們要的(通常試試看就知道是不是我們要的了)。
event6
圖:給button加一個click的event

然後就可以開始寫code了!這一行是利用剛剛設定的ID來拿到左邊的tree,並將它收合。
code6
圖:將左邊的tree收合

簡單吧!到這邊已經可以lay出複雜且會動的UI了!

Data Model與Store
在企業的web application中,前端需要的資料大多從後端DB過來。只要是有『吃資料』的元件,都需指定一個store給它,裡面存有前端畫面需要的所有資料。在store裡面需定義該store所需要存取的欄位(可以直接在store的fields屬性中定義欄位,也可以指定一個定義好的Data Model給它。)。以combo box(下拉選單)為例,它通常需要兩個欄位:顯示文字與實際值。
依照與後端溝通的方式,Ext提供了各種不同的proxy供store使用。另外根據回傳的資料形式不同,也提供了不同的reader供proxy使用。像我最常用的應該是Ajax Proxy搭配Json Reader。舉例來說,若是我們要做一個性別的選單,而資料由後端某個URL傳回來的Json格式如下:

  1. {
  2.     “total”: 2,
  3.     “data”: [
  4.         {“gender”: “M”, “genderText”: “男性”},
  5.         {“gender”: “F”, “genderText”: “女性”}
  6.     ]
  7. }

則需在store新增兩個field:gender和genderText;在proxy的url打上該URL;在reader的root屬性設成”data”(請看上面的json,我們要的資料是在data裡面)。

我知道這又是個爛例子,因為性別其實hard-code就好了XD。下圖是hard-code的combo box store作法: 建立一個Json Store,在field內加兩個欄位;在data裡面hard-code我們的資料;將proxy砍掉。
store6
圖:Store裡的設定

Combo box部分,將store指向上面定義的MyJsonStore;將displayField跟valueField分別設成我們的顯示文字與實際值欄位名;將queryMode設成”local”(若設成remote,當user在combo box敲字篩選時,會在url後面加上?query=xxx然後去問後端,方便後端做篩選處理)。
combo4
圖:Combo box裡的設定

佈署到local並預覽
剛看到Sencha Architect畫面時,一定會想試試看preview跟deploy按鈕到底是在做啥。其實也沒啥,就是幫我們deploy到web server再開啟瀏覽器預覽。須先在settings設定路徑如下圖。另外建議將Ext JS Path改成4.1的http://extjs.cachefly.net/ext-4.1.0-gpl/。
settings5
圖:專案設定畫面

Application及MVC架構
雖然這超出本文涵蓋的主題,但還是稍微談一下好了。當Web App規模大到一定程度時,想必會開始思考如何組織程式碼,讓它可讀性變高,還有方便maintain、動態載入及效能等等架構面的問題。若是有看過backbone.js、require.js、knockout.js等工具的介紹文,應該會對現在流行的架構概念有所認識。其實Ext JS也有它自己類似AMD的機制;如果要做類似backbone的hash routing,也可以透過Ext.history(但它還是用hidden iframe囧 要支援舊瀏覽器沒辦法);最重要的,它的MVC架構設計也是相當優秀,值得另開專文深入討論之。若想瞭解,可以參考這篇官方介紹。看完之後,相信會迫不及待地從左邊工具箱拖出controller來玩玩看吧!

好文分享:
Ext JS 4的Application/MVC架構概觀
Deft JS: Loosely Coupled MVC through Dependency Injection – John Yanarella
下面這幾個archticture tool相關文章也非常值得看看,但跟Ext沒關係
Backbone.js X RequireJS Quick Guide – 大澤木小鐵
介紹Knockout.js的MVVM:Understanding MVVM – A Guide For JavaScript Developers – Addy Osmani

整合後端開發
在瞭解他匯出的行為之後,就會發現其實很容易跟後端開發的專案進行整合。其中會遇到的一個問題就是他跑AMD動態載入JS Class時的路徑是否跟專案中的目錄架構是一樣的,這時候就要對Ext.application中的appFolder屬性做調整。我去年的一篇文章是以Java EE的Web project為例,將Ext Designer 1.2整合Eclipse進行開發。
好文分享:
Node.js+mongodb+EditGrid範例

IE8效能問題
這年頭很多人都愛用Firefox或Chrome進行開發,但是很遺憾的,咱們user可沒那麼先進。更令人沮喪的是Ext JS 4.0至4.0.7版本在IE8以下都有嚴重的效能問題。Sencha的解釋如下:

Ext JS 4 features a brand new rendering pipeline that is significantly more structured and extensible than the rendering process in Ext JS 3. All Components now render the same way, and are driven by XTemplates. They also follow a common hook point regime, enabling the framework and developers to extend or hook into the render process for each Component.
While the new rendering architecture is a big step forward, it did create slow performance in some cases. In 4.0.1 and before the order of operations in the rendering process was not as efficient as it could have been, resulting in many more DOM updates than are actually needed. In 4.0.2 we have corrected this behavior, yielding significant render speed improvements.
We have already identified further optimizations to the rendering pipeline that will be incorporated into Ext JS 4.0.3 and beyond. Performance is very important to all of us and making the framework as fast as we know it can be will remain a top priority for the team.

因此這次公開的4.1版主要就是focus在解決在IE的效能問題,現在已經有改善許多。 但是,在開發期間,良心建議您偶爾還是把IE開來跑跑看,免得像小弟當初一樣,發現時已經距引咎辭職(刪除線)上線的日子不遠矣!

在Linux下,SVN服务器的权限配置

言归正传,按照前面的教程装完1.5.5版以后,当svnadmin create /home/svn/yourproject创建仓库后,应该在仓库目录下的config目录有3个文件——authz、passwd、svnserve.conf。

下面对3个文件进行说明:

svnserve.conf是基础的配置,用于控制访问的权限将[general]前的注释与空格去掉,一定要去掉空格,否则到时客户端登录会出现”Section header must start in the first column的”的告警!亲身体会啊!!最后此文件内容至少包含以下内容:

[general]

anon-access = none

auth-access = write

password-db = passwd

authz-db = authz

其中,anon-access = none禁止匿名登录,auth-access = write为署名登录获得写权限,password-db = passwd指定用户配置文件,authz-db = authz指定权限配置文件

————————————————

passwd是用户配置文件,用于设置用户名以及密码

格式为:

[users]

<用户1> = <密码1>

<用户2> = <密码2>

其中用户名,密码不能为中文,至少我设中文登录时提示没有该用户

[users]是必须的。下面列出要访问svn的用户,每个用户一行。

示例:

[users]

alan = password

king = hello

这个里面的user表示当前test版本库的成员

——————————————————

authz是详细的用户授权文件

格式如下(以下内容转载,感谢原创):

  用户组格式:

[groups]

<用户组名> = <用户1>,<用户2>

  其中,1个用户组可以包含1个或多个用户,用户间以逗号分隔。用户必须要在passwd文件里能找到,它是给那个里面的user赋权限.

  版本库目录格式:

[/目录]

@<用户组名> = <权限>

<用户名> = <权限>

  示例:

  [groups]

  admin = alan

  [/]

  @admin = rw

  [/svn/p1/WebProject]

  king = rw(表示king能够读写/svn/p1/WebProject目录下的所有信息)

  [/svn/p1/web]

  zp=r(表示zp能够读/svn/p1/web目录下的所有信息)

————————————

以下是自己的体会:

注意:@admin代表整个组,king 在这里只是一个用户

关于访问路径[/目录],其完整格式[repos-name:path]或者[path],repos-name是版本库的名字

注意:在authz中如果要设定中文文件夹的路径,例如[/测试],请在linux在双击文件用默认记事本打开,然后另存为,注意将编码格式改为UNICODE UTF-8,否则在windows下用TortoiseSVN进行操作时,该中文路径的权限设置会有问题!此乃我的实际测试

当你用的中文svn客户端,并且又出现[瘉澶辫触]的错误不能够签入和签出,那么请检查authz的[path]权限等是否正确

Linux下关于subversion权限配置问题

我们在Linux下安装svn时,会发现这么一个问题,所有配置svn的过程自己都认为成功了,为什么一到客户端访问就会出现这样的提示呢:

Authorization failed

其实这个是权限配置的问题,说白了就是目录没配置对,并且你也没访问对。其实svn的配置不是很难,难的是你怎么用你清晰的思路去理解,以下说一下我是怎么进行配置的:

Subversion启动时候一定要注意应该启动哪个目录,这个细节将直接影响到你最后将给予目录权限的配置文件authz上面。

1、启动: svnserve –d –r /

这样的话在authz里就该:

[test:/] //可以访问test目录下所有文件(test是我在/根下建立的一个文件夹)

086php = rw //具有读写权限

? = r // 除了上面的用户,其他用户只有读的权限

客户端访问应该是这样:

IP test 例:svn://192.168.0.1/test

例如我想访问svn://192.168.0.1 下的所有目录,那么我们就得需要更新svn运行的目录,以及authz文件了。(test是我的仓库)

2、启动:svnserve –d –r /test

Authz文件内容:

[/]

086php = rw

这样你就可以直接访问svn://192.168.0.1目录下的所有文件,其实也就是我的仓库test下的所目录

3、如果你想访问test下的一个目录的话:

启动:svnserve –d –r /

Authz:

[test:/其他目录]

086php = rw

以后访问地址将:svn://192.168.0.1/目录

4、启动:svnserve –d –r /test

Authz:

[/其他目录即可,无需加test仓库名]

086php = r

访问地址变成了:

svn://192.168.0.1/其他目录

音乐是数学的奇迹

前一阵校内上流行一个matlab演奏《卡农》的帖子,写法蛮帅的,用的还是纯律而非平均律。回想起我初中时候在少科站无聊也用Turbo Pascal编过《亚洲雄风》来着,当时就觉得一串数字转化成音乐是件很神奇的事情。来聊聊音乐和数学哈~

音乐之所以和谐美妙,很大程度上得益于两个数学上的约等式同时成立:

1)  2 ^ (7/12) = 1.4983 ≈ 3/2,误差 0.1%
2)  2 ^ (4/12) = 1.2599 ≈ 5/4,误差 0.8%

听起来很邪乎吧?待我慢慢道来……

 

【陪音】

唱歌的时候如果唱不上去了我们经常会“唱低八度”,这时候虽然声音低了许多,但与原唱并不冲突,与伴奏也仍然和谐。那为什么“八度”那么特殊呢?或者说,为什么差八度的音听着那么像呢?原来差八度的两个音其频率正好差两倍——比如中音do(钢琴正中的C,记作C4或c’)是261.6赫兹,而高音do(记作C5或c’’)是它的两倍523.3赫兹

那为什么频率差两倍就听起来像呢?这里需要引入陪音(upper partials)的概念。除了一些音色很纯的音(比如机器发出的正弦波)外,多数乐器演奏中除了激活原本频率的声波(基音)之外还会激活这些频率的整数倍,也就是陪音。当你按下钢琴的C4,这时空气中激荡着的不只有261.6赫兹的声波,还有523.3赫兹、784.9赫兹、1046.5赫兹等等,而这些陪音的不同强度正反映了乐器的音色。注意523.3赫兹是C5,1046.5赫兹是C6,但784.9赫兹并不是一个C音,我们后文会讲到784.9赫兹比较接近G5。也就是说,同一音名的两个音之间肯定有陪音的关系,但反之不成立——陪音不必须是同一音名。回到八度的问题:C5本身就是C4最近的一个陪音,C5的陪音也都是C4的陪音,所以弹C5时激活的音频弹C4时也会激活(当然强度不同),两个音听起来自然像啦~

 

【平均律】

搞清楚了啥是八度,那一个八度里的音又是怎么分的呢?大家知道七声调式中一个八度是7个基本音级、12个半音,2个半音等于一个全音。大调是“全全半全全全半”,小调是“全半全全半全全”。在巴赫开始提倡、现代普遍采用的十二平均律中,这12个半音是均匀分布的——从物理上讲,也就是半音阶中的音的频率形成一个等比数列。比如说C4是261.6赫兹,C5是523.3赫兹,而两者之间的11个音每个的频率是上一个的2 ^ (1/12) = 1.0595倍——C♯4是261.6 * 1.0595 = 277.2赫兹,D4是277.2 * 1.0595 = 293.7赫兹,依此类推。一个半音又可以分成100个音分(cent),差一个音分相当于频率差2 ^ (1/120) = 1.00579倍。一个八度也就是1200个音分。普通人对音高的辨别阈大概是20音分(0.2个半音),而音乐家可以达到5音分(0.05个半音),不同音高下的辨别阈还有所不同

为什么要用平均律,让所有音均匀分布呢?一个重要的原因是方便转调。比如周杰伦的《安静》,开始一直是B♭调,在唱到第二遍副歌“你要我说多难堪”的时候突然升了一个全音变成了C调——也就是之前的B♭变成C,C变成D,D变成E等等,但尽管音高变了旋律听起来还是一样的,唱也还是一个感觉,区别最多也就是转一下调情绪激动一点。这种转调后的不变性是平均律特有的,在其他一些律制(比如五度相生律、纯律中庸全音律)中不成立。同时这也意味着除平均律外,其他律制中每个调号的色彩都略有不同。这就是为什么亨德尔会偏好F大调和G小调(当时还没有平均律),而lady gaga就不那么在乎

 

【音程的协和】

前菜上完了,下面是主菜:音程的协和。协和(consonant)这个概念,操作定义大致就是听起来和谐、悦耳。在实证研究中一般是给参与者同时播放两个正弦音(这种音不带陪音,只有基音),调整其间的频率间隔,然后让参与者在7点量表上评价这个音程有多悦耳、多优美、多和谐之类。Plomp和Levelt的这篇论文里结合了前人和他们自己的实验结果,得到这样一条曲线来描述两个音的间隔与这个音程不协和程度的关系:

b_large_BS8q_4fd2000006f81262

图一:音程不协和度与音程中根音和冠音间隔半音数的关系(图出自《American Scientist》上的这篇文章,是P & L原文Fig.10的重新制作)

怎么样,这条曲线看起来很光滑圆润小正太吧?可如果是这样,难道两个音的间隔越大越协和?那为什么又要分协和音程和不协和音程呢?且慢,记得我们讲这只是两个基音之间的不协和程度,而考虑上两个音各自陪音之间的协和程度之后,这图就变成了下面的样子:

b_large_xlRE_2df800004f541261

图二:考虑陪音后的音程不协和度(出自《American Scientist》,P & L原文Fig.11的重新制作)

光滑圆润的小正太转眼变成了小刺猬,而且这刺还不是乱长,偏偏长在0、3、4、5、7、9、12这几条线附近,是不是很神奇?我反正觉得挺神奇的。原文中没有给详细的推导过程,于是我就自己尝试推导了一下(蓝字部分)

首先图一这个小正太,怎么看怎么像一个Gamma分布。我试了几次后发现它和Gamma (2,1)最为接近:

b_large_B06S_33fc00000eb81262

图三:用Excel自制的Gamma (2,1),和图一长得很像吧

这个曲线大概反映出我们听觉的特点:当两个纯音间隔很小(比如小于0.2个半音)时人耳难以分辨,因此感觉是完全协和的。当刚开始能够分辨出两个音的时候感觉特别刺耳,于是就出现了1-2个半音处不协和的高峰,而之后随着间隔变大刺耳的感觉逐渐减弱,不和谐度也下降了。Gamma (2,1) 模型的具体数值如下表

b_large_b78S_167b0000063b1261

表一:根据Gamma (2,1) 算出的不协和度数值(y轴无量纲)

接下来看陪音之间的协和。打个不太恰当的比方,谈恋爱不仅要两个人谈得来,还要讲究门当户对不是?所以说还要拿双方的弟弟妹妹们来配配看是否和谐,最后把所有不和谐的因素加起来看。表二中列出了根音6倍之内陪音和冠音8倍之内陪音的间隔半音数。从图三中看到两个音相差6个半音以上不协和程度就很低了,所以忽略掉陪音频率差别在3:2以上的情况(实际计算的时候我是忽略了2:1以上的情况)

b_large_miuK_561e000018ec1263

表二:根音陪音和冠音陪音的间隔半音数

把表二中的数值代入Gamma模型,就得到表三的不和谐度

b_large_SGgs_75b5000115681261

表三:根音陪音和冠音陪音的不协和度

把所有陪音的不协和度加起来就得到了图四,和American Scientist上的图(图二)差不多吧

b_large_VfZP_2002000006141263

图四:考虑陪音后的音程不协和度(Excel自制)

以上部分我们用一个Gamma模型推导了考虑陪音后根音-冠音间隔和音程不和谐度的关系。那么图上突然下降的那几根刺是怎么来的呢?

举例来讲,间隔半音数7附近不协和度突然下降,而这个下降主要来自根音的3倍音(橙色线)和6倍音(绿色线)。回到表三,可以看到7个半音(G4)这一栏下黑框中的两个数(0.02)远远小于黑框两边6个半音和8个半音两栏(0.37),使得G4的陪音与C4的3倍音、6倍音上的不和谐度只有两边F♯4和G♯4的10%不到。类似的情况也出现在0、3、4、5、9、12个半音的栏目中(表三中粗体标出)

之所以这些位置会出现不协和度突然下降,寻根溯源到表二就很清楚了:表三中标粗的位置在表二中都接近0(绝对值 < 0.2)。对照Gamma分布的曲线(图三)和之前的讨论,两个音相差小于0.2个半音时普通人难以分辨其差别,也就不会觉出不协和。而一旦稍高于这个阈限,不协和度就陡然上升。这也就解释了为什么会有“刺”及其两边的突起形状 还是以G4(和C4间隔7个半音)为例。G4的2倍音和C4的3倍音太过接近,以致听不出不协和。G4的4倍音和C4的6倍音,G4的6倍音和C4的9倍音等等也都如此。这样叠加的效果使得G4和C4构成的音程总体而言听起来不协和度低,也就解释了7附近的不协和度下降。注意,不管原图还是自制图中都只考虑了根音6倍以内的陪音,加上更高倍数陪音的话“刺”会更多

OK,如果还有人follow的话,以上冗长的推导简单来讲就是要证明这样一个结论:当根音和冠音的振动频率成简单整数比时,音程就协和。两者所成整数比越简单、越精确,音程就越协和

这个结论大体是得到实证数据支持的:我们通常听来协和的音程(图二中“刺”的位置)都可以近似表示成简单整数比,而不协和音程表示成整数比要么分子分母较大,要么误差较大(表四)。简单整数比也同样能解释一些三和弦的协和:比如同为大三度和小三度的叠加,大三和弦其三个音的比例是4:5:6从而听起来非常“正”,小三和弦三个音的比例是10:12:15协和程度就略差一些

b_large_0Xsg_4d5c0000a6de1262

表四:协和音程和不协和音程对应的振动频率比

 

【见证奇迹】

总结一下上面两部分说的:协和音程要求音阶中各个音的频率成简单整数比a/b,而平均律要求音阶在1和2之间构成等比数列,也即各个音的频率比需要表示为2^(m/n)(m为两个音的间隔数,n为一个八度音阶的全部音数)。也就是说,音程如果既要协和又要符合平均律的话,就必须有a/b = 2^(m/n)。但这里就产生了矛盾:a/b 是有理数,而2^(m/n) 在m非n整数倍的情况下是无理数,两者没法相等

怎么办呢?所幸人耳没那么精确,允许一定误差,也就是可以a/b ≈ 2^(m/n)。两边取以2为底的对数得 m/n ≈ log2 (a/b),或者写成m/n = log2 (a/b) + ε(标为*式),此处ε是平均律情况下音频比偏离简单整数比的误差。这个误差当然不能太大:前文提到一般人对音高的辨别阈大概在20音分左右,我们取15音分(听力稍好的人的辨别阈)作为标准,也就得到|ε| < 15/1200 = 0.0125 然后考虑简单整数比a/b:a/b为整数(1、2)时产生的是极完全和谐音程,这时候m/n = 0或1,必然有精确解。而我们关注的是其他协和音程,即a/b = 3/2, 4/3, 5/4, 6/5时能不能找到相应的m/n。而事实上,只要找到在a/b = 3/2(纯五度)和a/b = 5/4(大三度)情况下符合*式的m1/n和m2/n,其他常用协和音程也都迎刃而解。蓝字部分是解释了为什么存在纯五度和大三度后就能导出所有其他协和音程:

log2 (4/3) = 1 – log2 (3/2),log2 (3/2) 是有理数时log2 (4/3) 必是同分母的有理数,即存在纯五度也就存在纯四度
log2 (5/4) = 1 – log2 (8/5),存在大三度也就存在小六度
log2 (6/5) = log2 (3/2) – log2 (5/4),存在纯五度、大三度也就存在小三度
log2 (5/3) = 1 – log2 (6/5),存在小三度也就存在大六度

好,接下来的工作就是一个一个试了:下面列出了n在30以内所有接近纯五度的m1/n,m1/n ≈ log2 (3/2) = 0.585
7/12, 14/24
10/17
11/19
13/22
15/26
16/27
17/29

接近大三度的m2/n,m2/n ≈ log2 (5/4) = 0.322;红色标出的是既存在纯五度、也存在大三度的情况
1/3, 2/6, 3/9, 4/12, …
5/16
6/19
7/22
8/25
9/28
9/29

对比两串数,12这个神奇数字就这样华丽丽地登场了:在12平均律下相差7个半音的音程可以满足纯五度(12是满足该条件最小的n),而恰好此律下相差4个半音的音程可以满足大三度

你或许说如果没有12平均律,那19平均律、22平均律也行啊——且慢,让我们把纯五度的纯度要求提高些(毕竟这是完全协和音程),取到音乐家的辨别阈5音分(|ε| < 5/1200 = 0.0041)来看看。这时12平均律仍然满足要求,而19平均律、22平均律则被踢出。下一个满足要求的是29平均律,遗憾的是29平均律的大三度没有12平均律的纯,以至于如果需要找一个真正比十二平均律更纯的平均律,最小也要41平均律 现在看出奇迹所在了吧?如果没有12平均律而要用41平均律,那钢琴上弹一个八度需要手跨41个键,而钢琴的琴键总数将达到300个……更重要的是,41平均律中两个相邻音之间只差不到30音分,实在不好辨别啊…… 恩,这也就是我要说的,音乐美妙多亏一个数学的巧合,说夸张点就是“音乐是数学的奇迹”。再来回顾一下这两个神奇的式子: 7/12 = log2 (3/2) – 0.0016
4/12 = log2 (5/4) + 0.0114
两边取2的幂次就得到文章开头的两个式子了

 

【不只是数学】

相信较真儿的同志肯定发现了不少问题:上述模型中小六度应该是不协和的,而实际乐理中认为小六度是协和音程;模型只考虑了根音6倍音以下的情况,而没说明为什么取6倍;用Gamma分布描述人耳对不协和程度的感知缺乏理论依据,等等。确实,这个模型有很多简化和不足的地方。而且我只是关注单音程协和的问题,要解释三和弦、四和弦的协和,乃至和弦进行的问题就要复杂得多了(这里有解释三和弦和谐程度的几个模型,简化中文版看这里

进一步说,协和又怎么样,协和的音乐就好听吗?这个答案必须是否定的。欧洲中世纪和中国古代都有“音乐之美在于和谐”的思想,进而产生出像复调音乐“奥加农”和中国的“雅乐”这样追求绝对协和的音乐。以奥加农为例,全部依平行四度、平行五度进行,但其结果是音乐过于空洞、苍白,为历史所淘汰。平行五八度的进行也因为过于协和而在古典乐理中被禁掉。现代音乐那就更自由了:爵士、布鲁斯的和弦进行就与古典音乐有明显差别,而现代主义的无调性音乐就完全没有协和可谈了。所以说协和只是音乐之美的一个方面,节奏、音色、曲式、歌词等等往往起到更大的影响。不过说实在的,作为一个俗人,还是听协和点的音乐比较舒服啊~

 

草鱼原创,转载请注明

 

参考文献:
《律制详解》
【和专题】跟我和一曲阿卡贝拉,by悠扬
Cook N.D. & Hayashi T. (2008).The Psychoacoustics of Harmony Perception. American Scientist, July-August: 311-319.
Plomp, R., & Levelt, W.J.M. (1965). Tonal consonances and critical bandwidth. Journal of the Acoustical Society of America, 38, 548-560.

 

————————————————————————————————————————————————————
没想到浏览量破万了,非常感谢大家的支持和分享。我不是学音乐也不是学数学的,只是业余感兴趣,懂得很皮毛。不过乐理还真是个老少咸宜的话题,欢迎一起探讨。顺便推荐几个其他的数学帖:

所有的数都可以用二十个以内的汉字表达?
Impossible Puzzle

Manufactoria! 

厚脸皮一下,再链几个原创旅游帖:

坦桑尼亚游记之“大七”
秘鲁游记之神兽家谱
阿根廷游记之攻略篇