This channel is used to output white noise. This is done by randomly switching the amplitude between high and low at a given frequency. Depending on the frequency the noise will appear 'harder' or 's ofter'.
It is also possible to influence the function of the random generator, so the that the output becomes more regular, resulting in a limited ability to output Tone instead of Noise.
REG_SOUND4CNT_L†
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.
REG_SOUND4CNT_H†
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;
}
}
}