Question about Channel 3 Waveform

Discussion of programming and development for the original Game Boy and Game Boy Color.
Post Reply
venge
Posts: 2
Joined: Sun Aug 10, 2014 4:50 am

Question about Channel 3 Waveform

Post by venge »

Hi,
I managed to get the two square channels in my emulator play correctly. Now I'm in the process of creating the channel 3, but I think I'm really stuck. In Blargg's "Game Boy Sound Operation" at "Wave Channel" it says:
The wave channel's frequency timer period is set to (2048-frequency)*2.
When the timer generates a clock, the position counter is advanced one
sample in the wave table, looping back to the beginning when it goes
past the end, then a sample is read into the sample buffer from this NEW
position.
Now what does that mean in raw practice? I got it like this in my mind (pseudo):

Code: Select all

channel3_clocks += CPU.clock; //increment a counter with cpu clocks
if(channel3_clocks >= frequency) {
    advance_one_sample(); 
    get_sample_amplitude();
    channel3_clocks -= frequency;
}
Apparently this is SO BAD as it sounds, but is there any other way to implement it using only the cpu clocks? Or I'm missing a lot of things here.

Thank you very much.
Shonumi
Posts: 342
Joined: Sun Jan 26, 2014 9:31 am

Re: Question about Channel 3 Waveform

Post by Shonumi »

One thing to verify is that you have the playback/output frequency of Sound 3 correctly calculated. At least for me, I misread the documentation and had the frequency playing twice as fast. Sound 3's Frequency Timer actually runs at half the rate of Sound 1 and Sound 2's, so naturally the playback/output frequency of the sound itself is half of Sound 1 and Sound 2. Make sure you calculate the frequency as 65536/(2048-x) Hz where x represents Bits 0-2 of NR34.

To calculate the period (in GB CPU cycles) you just do 4194304 / (65536/(2048-x)). So if x is 0, you get an output frequency of 32 Hz, meaning your period is 131072 CPU cycles. In the case where x = 0, your if statement would have to check if channel3_clocks is greater than or equal to 131072.

But you have the right idea. Whenever you clock the frequency timer (cpu cycles >= frequency timer), you advance one step in the Wave Table, grab the amplitude of the step, and continue generating audio samples. Have you tried running any code yet? I'm probably the last person to give you advice on this subject though. My APU emulation doesn't even count CPU cycles, and my Sound 3 code is atrociously inaccurate, but it somehow manages to work 98% of the time :p Though I need to fix that soon. Anyone can feel free to correct me since I am not the best when it comes to sound programming or maths.
venge
Posts: 2
Joined: Sun Aug 10, 2014 4:50 am

Re: Question about Channel 3 Waveform

Post by venge »

oh, hello.
Shonumi wrote:Make sure you calculate the frequency as 65536/(2048-x) Hz where x represents Bits 0-2 of NR34.
Actually, at channel INIT I was grabbing NR34 bits 2-0, and all bits of NR33, OR them to get 11bit frequency, subtract them from 2048 and multiply the result with 2. Then compare it with cpu cycles (cpu cycles >= frequency timer as you said) to hear just static (like a mic with a bad cable). Although I ran a square channel on that frequency, the same way I run channels 1 & 2 and it played correctly (in square of course). The problem is my timings advancing the wave sample: I think i'm advancing it VERY slowly, hence the static (it's like i'm changing DC offsets fast, which is not fast enough to be considered a wave).
Shonumi wrote: To calculate the period (in GB CPU cycles) you just do 4194304 / (65536/(2048-x)). So if x is 0, you get an output frequency of 32 Hz, meaning your period is 131072 CPU cycles. In the case where x = 0, your if statement would have to check if channel3_clocks is greater than or equal to 131072.
Ok, I totally aggree, but no matter how small the frequency, I just hear static. Shouldn't I consider sample rate somewhere in the phase/time calculations?
Shonumi wrote:My APU emulation doesn't even count CPU cycles, and my Sound 3 code is atrociously inaccurate, but it somehow manages to work 98% of the time :p
:D ! My APU doesn't count clocks at channels 1 & 2 too! xD. That's why I find it hard to get chann 3 working i believe.

edit: Actually after playing with my sound (laughing hard after each result), I came up with a code that slightly reminded me of channel 3 in some games. The practice is the worst possible: Keep track of phase 0-2π . Divide phase by 32 this gives 0.196. After 0.196 (rads?) I advance one sample. It's not better than having no channel 3 at all, but at least it reminded me of something :D

edit2:
Ok I think i got it working now (with this nasty way as well):

Code: Select all

public float update_wave(float volume) {
            sample_num = (int)(phase * 5.09);
            byte sample = Memory.mem[0xFF30 + sample_num / 2];

            if (sample_num % 2 == 0) {
                amplitude = ((sample >> 4) - 8);
            }
            else amplitude = ((sample & 0xF) - 8);

            phase = phase + ((Math.PI * frequency) / 44100);

            if (phase > 2 * Math.PI) {
                phase = phase - (2 * Math.PI);
            }
            return amplitude * 0.0625f * volume;
}
Don't ask me why it works. But if you think it, it's quite logic. 32 / (2 * π) = 5.09 . Each gives one sample. So I multiply phase with 5.09, apparently giving me the sample number. And so, this is the ratio of period-to-game boy sample.
Post Reply