NES 模擬器開發(fā)教程 13 - APU 簡介

通過前面的教程基本已經(jīng)能玩游戲了群嗤,但是有音樂才算得上完整,下面介紹 NES 的 APU

1. 簡介

APU 和 PPU 一樣托享,也是比較復(fù)雜的芯片,和 PPU 比起來簡單一些浸赫,但是比 CPU 復(fù)雜闰围,畢竟不具備通用性

APU 有 5 通道,2 個(gè)方波既峡,1 個(gè)三角波羡榴,1 個(gè)噪聲,1 個(gè) DMC

注:DMC 全稱為 delta modulation channel运敢,它用來產(chǎn)生方波校仑,三角波,噪聲產(chǎn)生不了的聲音传惠,聲音信息提前存入 rom 中迄沫,不考慮精度的情況下,可以生成任意波形卦方,比如鼓聲這種復(fù)雜的聲音羊瘩,就得用 DMC

NES 有 4 bit DAC,故電壓范圍為 0 - 15盼砍,但是 DMC 除外尘吗,它有 7 bit,范圍為 0 - 127

注:DAC 叫 “數(shù)模轉(zhuǎn)換器”浇坐, 作用是把數(shù)字量轉(zhuǎn)化為模擬量(電壓)睬捶,音頻信號(hào)就是典型的模擬信號(hào),其電壓隨時(shí)間變化近刘,所以通過 DAC擒贸,可以通過數(shù)字的方式生成音頻信號(hào)臀晃。

APU 寄存器分布如下:

通道 地址 操作
方波1 (pulse1) 0x4000 - 0x4003 w
方波2 (pulse2) 0x4004 - 0x4007 w
三角波 (triangle) 0x4008 - 0x400B w
噪聲 (noise) 0x400C - 0x400F w
DMC 0x4010 - 0x4013 w
狀態(tài)寄存器 0x4015 rw
幀計(jì)數(shù)器 0x4017 w

2. 時(shí)鐘

聲音有長有短,頻率也在時(shí)刻變化酗宋,這些都需要時(shí)鐘來提供积仗,APU 有兩個(gè)時(shí)鐘:

  • 基本時(shí)鐘(APU 周期):CPU clock / 2
    用于控制波形頻率
  • 幀計(jì)數(shù)器:240Hz
    用于控制波形持續(xù)時(shí)間

3. 狀態(tài)寄存器

由于 APU 有多個(gè)通道,所以提供了專門的 狀態(tài)寄存器 用于控制通道使能和讀取通道相關(guān)信息

  • 寫 0x4015

    BIT 作用
    0 使能方波 1
    1 使能方波 2
    2 使能三角波
    3 使能噪聲
    4 使能 DMC
    5 -
    6 -
    7 -
  • 讀 0x4015

    BIT 作用
    0 方波 1 長度計(jì)數(shù)器不為 0
    1 方波 2 長度計(jì)數(shù)器不為 0
    2 三角波長度計(jì)數(shù)器不為 0
    3 噪聲長度計(jì)數(shù)器不為 0
    4 DMC 長度計(jì)數(shù)器不為 0
    5 -
    6 幀中斷
    7 DMC 中斷

讀 0x4015 后蜕猫,會(huì)清除 幀中斷 標(biāo)志

4. 幀計(jì)數(shù)器

幀計(jì)數(shù)器 位于地址 0x4017寂曹,用來驅(qū)動(dòng)各通道的長度,包絡(luò)等單元回右。該寄存器只用了 2 個(gè) bit隆圆,分別控制中斷使能與步進(jìn)方式:

BIT 作用
0 0:4 步模式,1:5 步模式
1 中斷禁止標(biāo)志翔烁,0:使能中斷渺氧,1:禁用中斷
2 - 7 -

這里肯定有人不理解什么是 4 步 5 步模式,還記得前面時(shí)鐘部分講到有 240Hz 的時(shí)鐘嗎蹬屹?該時(shí)鐘每周期會(huì)步進(jìn)一次侣背,如下:

4 步模式 5 步模式 功能
- - - f - - - - - 產(chǎn)生中斷
- l - l - l - - l 驅(qū)動(dòng)長度計(jì)數(shù)器(Length counter)和掃描單元(Sweep)
e e e e e e e - e 驅(qū)動(dòng)包絡(luò)(Envelope)與線性計(jì)數(shù)器(Linear counter)

注:長度計(jì)數(shù)器,包絡(luò)等概念一會(huì)再講

比如慨默,如果當(dāng)前為 4 步模式贩耐,則驅(qū)動(dòng)包絡(luò)與線性計(jì)數(shù)器的頻率為 240Hz,產(chǎn)生中斷的頻率為 60Hz厦取,驅(qū)動(dòng)長度計(jì)數(shù)器和掃描單元的頻率為 120Hz

用代碼實(shí)現(xiàn)也很簡單潮太,用 switch case 就行:

  // processFrameCounter 調(diào)用頻率為 240Hz
  private processFrameCounter(): void {
    if (this.mode === 0) { // 4 Step mode
      switch (this.frameCounter % 4) {
        case 0:
          this.processEnvelopeAndLinearCounter();
          break;
        case 1:
          this.processLengthCounterAndSweep();
          this.processEnvelopeAndLinearCounter();
          break;
        case 2:
          this.processEnvelopeAndLinearCounter();
          break;
        case 3:
          this.triggerIRQ();
          this.processLengthCounterAndSweep();
          this.processEnvelopeAndLinearCounter();
          break;
      }
    } else { // 5 Step mode
      switch (this.frameCounter % 5) {
        case 0:
          this.processEnvelopeAndLinearCounter();
          break;
        case 1:
          this.processLengthCounterAndSweep();
          this.processEnvelopeAndLinearCounter();
          break;
        case 2:
          this.processEnvelopeAndLinearCounter();
          break;
        case 3:
          break;
        case 4:
          this.processLengthCounterAndSweep();
          this.processEnvelopeAndLinearCounter();
          break;
      }
    }
  }

5. 單元

前面已經(jīng)見過了長度計(jì)數(shù)器(Length counter),掃描單元(Sweep)虾攻,包絡(luò)(Envelope)铡买,線性計(jì)數(shù)器(Linear counter),每個(gè)通道都包含部分上述單元霎箍,每通道的單元都可以由該通道的寄存器控制奇钞,單元列表如下:

通道 單元
方波1 (pulse1) Timer, length counter, envelope, sweep
方波2 (pulse2) Timer, length counter, envelope, sweep
三角波 (triangle) Timer, length counter, linear counter
噪聲 (noise) Timer, length counter, envelope, linear feedback shift register
DMC Timer, memory reader, sample buffer, output unit
  • Timer
    每個(gè)通道都有,它使用基本時(shí)鐘(CPU clock / 2)漂坏,用于控制波形頻率
  • Length counter(長度計(jì)數(shù)器)
    除 DMC 外其他通道都有蛇券,用于控制波形持續(xù)時(shí)間
  • Envelope(包絡(luò))
    只有方波和噪聲通道有,用于控制音量隨時(shí)間的變化的情況樊拓,比如車離你越來越遠(yuǎn)纠亚,音量越來越小的場景
  • Sweep(掃描單元)
    只有方波通道有,用于控制聲音頻率隨時(shí)間變化筋夏,可以想象下汽車車速越來越快時(shí)發(fā)動(dòng)機(jī)聲音越來越尖的場景
  • Linear counter (線性計(jì)數(shù)器)
    只有三角波通道有蒂胞,與 Length counter 一樣,也用來控制音頻持續(xù)時(shí)間条篷∑妫肯定有人會(huì)問這樣功能不就重復(fù)了嗎蛤织。其實(shí)結(jié)合前面的 4 步與 5 步序列我們可以發(fā)現(xiàn),Linear counter 一個(gè)周期處理 4 次鸿染,Length counter 一個(gè)周期只處理 2 次指蚜,這樣 Linear counter 的精度就是 Length counter 的 2 倍,可以做更高精度的定時(shí)
  • linear feedback shift register(線性反饋移位寄存器)
    只有噪聲通道有涨椒,用來發(fā)生偽隨機(jī)數(shù)摊鸡,以此來產(chǎn)生噪聲
  • Memory reader(內(nèi)存讀取單元)
    只有 DMC 通道有,讀取總線上編碼好的數(shù)據(jù)到 sample buffer
  • Sample buffer(采樣緩沖)
    只有 DMC 通道有蚕冬,緩沖 DMC 數(shù)據(jù)
  • Output unit(輸出單元)
    只有 DMC 通道有免猾,用于生成音量數(shù)據(jù)

6. 混音器

復(fù)雜的音樂是有各t種音色組合起來的,APU 5 個(gè)通道充分運(yùn)用才能發(fā)出動(dòng)聽的音樂囤热×蕴幔混音器就是用來組合 5 個(gè)通道音頻整合后輸出一個(gè)信號(hào)的東西

下列公式會(huì)將 5 個(gè)通道聲音整合后輸出為一個(gè)范圍 0 ~ 1.0 的信號(hào):

output = pulse_out + tnd_out

                            95.88
pulse_out = ------------------------------------
             (8128 / (pulse1 + pulse2)) + 100

                                       159.79
tnd_out = -------------------------------------------------------------
                                    1
           ----------------------------------------------------- + 100
            (triangle / 8227) + (noise / 12241) + (dmc / 22638)

具體參考 http://wiki.nesdev.com/w/index.php/APU_Mixer

在模擬的時(shí)候混音器有兩種實(shí)現(xiàn)方式:查表和直接計(jì)算,直接計(jì)算代碼最簡單:

    output = pulse_out + tnd_out
    
    pulse_out = 0.00752 * (pulse1 + pulse2)
    
    tnd_out = 0.00851 * triangle + 0.00494 * noise + 0.00335 * dmc
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旁蔼,一起剝皮案震驚了整個(gè)濱河市锨苏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棺聊,老刑警劉巖伞租,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躺屁,居然都是意外死亡肯夏,警方通過查閱死者的電腦和手機(jī)经宏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門犀暑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人烁兰,你說我怎么就攤上這事耐亏。” “怎么了沪斟?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵广辰,是天一觀的道長。 經(jīng)常有香客問我主之,道長择吊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任槽奕,我火速辦了婚禮几睛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粤攒。我一直安慰自己所森,他們只是感情好囱持,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焕济,像睡著了一般纷妆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晴弃,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天掩幢,我揣著相機(jī)與錄音,去河邊找鬼肝匆。 笑死粒蜈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的旗国。 我是一名探鬼主播枯怖,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼能曾!你這毒婦竟也來了度硝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤寿冕,失蹤者是張志新(化名)和其女友劉穎蕊程,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驼唱,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡藻茂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玫恳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辨赐。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖京办,靈堂內(nèi)的尸體忽然破棺而出掀序,到底是詐尸還是另有隱情,我是刑警寧澤惭婿,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布不恭,位于F島的核電站,受9級(jí)特大地震影響财饥,放射性物質(zhì)發(fā)生泄漏换吧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一钥星、第九天 我趴在偏房一處隱蔽的房頂上張望沾瓦。 院中可真熱鬧,春花似錦、人聲如沸暴拄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乖篷。三九已至响驴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撕蔼,已是汗流浹背豁鲤。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鲸沮,地道東北人琳骡。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像讼溺,于是被迫代替她去往敵國和親楣号。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容