サウンド4はホワイトノイズを作ります。各パラメータの関係は以下のとおりです。
主役1 | Frequency Ratio | |
主役2 | Frequency Shift | |
引き立て役1 | Sound length | 音の長さ |
引き立て役2 | Envelope | 初期音量、減衰増幅、変化量 |
引き立て役3 | Counter Step | 一定の速度での周波数変化 |
REG_SOUNDCNT_X = 0x80; // turn on sound circuit REG_SOUNDCNT_L = 0x8877; // full volume, enable sound 4 to left and right REG_SOUNDCNT_H = 2; // Overall output ratio - Full
4000078h - SOUND4CNT_L (NR41, NR42) - Channel 4 Length/Envelope (R/W) Bit Expl. 0-5 W Sound length; units of (64-n)/256s (0-63) 6-7 - Not used 8-10 R/W Envelope Step-Time; units of n/64s (1-7, 0=No Envelope) 11 R/W Envelope Direction (0=Decrease, 1=Increase) 12-15 R/W Initial Volume of envelope (1-15, 0=No Sound) 16-31 - Not used The Length value is used only if Bit 6 in NR44 is set.
400007Ch - SOUND4CNT_H (NR43, NR44) - Channel 4 Frequency/Control (R/W) The amplitude is randomly switched between high and low at the given frequency. A higher frequency will make the noise to appear 'softer'. When Bit 3 is set, the output will become more regular, and some frequencies will sound more like Tone than Noise. Bit Expl. 0-2 R/W Dividing Ratio of Frequencies (r) 3 R/W Counter Step/Width (0=15 bits, 1=7 bits) 4-7 R/W Shift Clock Frequency (s) 8-13 - Not used 14 R/W Length Flag (1=Stop output when length in NR41 expires) 15 W Initial (1=Restart Sound) 16-31 - Not used Frequency = 524288 Hz / r / 2^(s+1) ;For r=0 assume r=0.5 instead Noise Random Generator (aka Polynomial Counter) Noise randomly switches between HIGH and LOW levels, the output levels are calculated by a shift register (X), at the selected frequency, as such: 7bit: X=X SHR 1, IF carry THEN Out=HIGH, X=X XOR 60h ELSE Out=LOW 15bit: X=X SHR 1, IF carry THEN Out=HIGH, X=X XOR 6000h ELSE Out=LOW The initial value when (re-)starting the sound is X=40h (7bit) or X=4000h (15bit). The data stream repeats after 7Fh (7bit) or 7FFFh (15bit) steps.
#include "lib/gba.h" #include "irq.arm.h" #include "key.h" #include "mode3.h" //--------------------------------------------------------------------------- typedef struct { s32 cur; // 現在値 s32 min; s32 max; s32 adj; // 増減値 } ST_PARAM; //--------------------------------------------------------------------------- void DrawParam(ST_PARAM* p) { for(s32 i=0; i<8; i++) { Mode3DrawPrintf(20, 5+i, "%04X", p[i].cur); } if(p[2].cur == 0) Mode3DrawStr(25, 5+2, "(Dec)"); else Mode3DrawStr(25, 5+2, "(Inc)"); if(p[5].cur == 0) Mode3DrawStr(25, 5+5, "(15 steps)"); else Mode3DrawStr(25, 5+5, "( 7 steps)"); switch(p[8].cur) { case 0: Mode3DrawStr(20, 5+8, "9-bits/32768 Hz "); break; case 1: Mode3DrawStr(20, 5+8, "8-bits/65536 Hz "); break; case 2: Mode3DrawStr(20, 5+8, "7-bits/131072 Hz"); break; case 3: Mode3DrawStr(20, 5+8, "6-bits/262144 Hz"); break; } u16 L, H; L = (p[3].cur<<12) + (p[2].cur<<11) + (p[1].cur<< 8) + p[0].cur; H = (p[7].cur<<14) + (p[6].cur<< 4) + (p[5].cur<< 3) + p[4].cur; Mode3DrawPrintf(33, 0, "%04X", L); Mode3DrawPrintf(33, 1, "%04X", H); } //--------------------------------------------------------------------------- int main(void) { REG_WSCNT = 0x4317; Mode3Init(); IrqInit(); KeyInit(); ST_PARAM param[9]; bool isSnd = FALSE; s16 sel = 0; _Memset(¶m, 0x00, sizeof(param)); param[ 0].cur = 0x0; param[ 1].cur = 0x7; param[ 2].cur = 0x0; param[ 3].cur = 0xF; param[ 4].cur = 0x6; param[ 5].cur = 0x1; param[ 6].cur = 0x3; param[ 7].cur = 0x0; param[ 8].cur = 0x3; param[ 0].min = 0x0; param[ 1].min = 0x0; param[ 2].min = 0x0; param[ 3].min = 0x0; param[ 4].min = 0x0; param[ 5].min = 0x0; param[ 6].min = 0x0; param[ 7].min = 0x0; param[ 8].min = 0x0; param[ 0].max = 0x3F; param[ 1].max = 0x7; param[ 2].max = 0x1; param[ 3].max = 0xF; param[ 4].max = 0x7; param[ 5].max = 0x1; param[ 6].max = 0xF; param[ 7].max = 0x1; param[ 8].max = 0x3; param[ 0].adj = 0x1; param[ 1].adj = 0x1; param[ 2].adj = 0x1; param[ 3].adj = 0x1; param[ 4].adj = 0x1; param[ 5].adj = 0x1; param[ 6].adj = 0x1; param[ 7].adj = 0x1; param[ 8].adj = 0x1; Mode3DrawStr(2, 0, "0x04000078 (REG_SOUND4CNT_L) = "); Mode3DrawStr(2, 1, "0x0400007C (REG_SOUND4CNT_H) = "); Mode3DrawStr(2, 5, "Sound Length :"); Mode3DrawStr(2, 6, "Envlp Step Time :"); Mode3DrawStr(2, 7, "Envlp Step Dir :"); Mode3DrawStr(2, 8, "Envlp Init Vol :"); Mode3DrawStr(2, 9, "Frequency Ratio :"); Mode3DrawStr(2, 10, "Counter Step :"); Mode3DrawStr(2, 11, "Shift Frequency :"); Mode3DrawStr(2, 12, "Length Flag :"); Mode3DrawStr(2, 13, "Resampling Freq :"); Mode3DrawStr(0, 5+sel, ">"); DrawParam(param); REG_SOUNDCNT_X = 0x80; // turn on sound circuit REG_SOUNDCNT_L = 0x8877; // full volume, enable sound 4 to left and right REG_SOUNDCNT_H = 2; // Overall output ratio - Full for(;;) { VBlankIntrWait(); KeyExec(); u16 rep = KeyGetRep(); u16 trg = KeyGetTrg(); if(rep & KEY_UP && sel > 0) { Mode3DrawStr(0, 5+sel, " "); sel--; Mode3DrawStr(0, 5+sel, ">"); } if(rep & KEY_DOWN && sel < 8) { Mode3DrawStr(0, 5+sel, " "); sel++; Mode3DrawStr(0, 5+sel, ">"); } if((rep & KEY_RIGHT) && (param[sel].cur < param[sel].max)) { param[sel].cur += param[sel].adj; DrawParam(param); isSnd = TRUE; } if((rep & KEY_LEFT) && (param[sel].cur > param[sel].min)) { param[sel].cur -= param[sel].adj; DrawParam(param); isSnd = TRUE; } if(isSnd == TRUE || trg & KEY_A) { u16 B, L, H; B = (param[8].cur<<14) + (REG_SOUNDBIAS & 0x3fff); L = (param[3].cur<<12) + (param[2].cur<<11) + (param[1].cur<< 8) + param[0].cur; H = (param[7].cur<<14) + (param[6].cur<< 4) + (param[5].cur<< 3) + param[4].cur; REG_SOUNDBIAS = B; REG_SOUND4CNT_L = L; REG_SOUND4CNT_H = H + TRIFREQ_RESET; isSnd = FALSE; } } }