It is currently Wed Dec 13, 2017 12:26 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Tue Apr 28, 2009 11:34 pm 
Offline

Joined: Wed Apr 22, 2009 12:47 am
Posts: 9
Hi Guys,

First of all it is great to see a gameboy dev forum here as I havent been able to find a decent one on the net. I have a fully working gameboy emulator and now just need to add sound support. I have previously posted on the nesdevemu forum asking for help with square waves because the sound chip on the gameboy and NES are very similar. I am now attempting to implement the wave channel and have come stuck. My main problem with this channel is knowing how to interpret the 32 samples in memory and how to play them. This channel has a frequency like the square wave channels so Im assuming that when enough clock cycles have passed and the frequency has decreased to 0 then you move onto the next sample in memory and reload the frequency and start counting down again (this is similar to how I handle square waves by counting down the frequency and upon 0 I increase the duty cycle and change the polarity if needed).

Does this sound correct so far?

My problem now is how to play the current sample. So if the sample Im playing has the value of 0xA what does this actually mean? You see with square waves I simply multiply the volume by the polarity (either +1 or -1) and total them all up before adding to the playback buffer, but im unsure how to do this with a wave. Also am I correct in assuming the value returned from a wave is +1 and 0 and not +1 and -1 like square waves? If so then how do I mix a wave and a squre wave before adding it to the playback buffer?

Thanks for your time and any help.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 29, 2009 12:59 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Have you read the wave section of the Game Boy Sound Hardware wiki page yet?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 29, 2009 1:30 am 
Offline

Joined: Wed Apr 22, 2009 12:47 am
Posts: 9
Thanks for the reply Blarrg.

I hadnt read that link before I posted I had only read Lord Nightmares GBSOUND.txt and also NESSOUND.txt to see if I could clarify anything in there.

I have briefly read that wiki page and it seems fantastic, exactly what I needed. Although I will probably post in this thread again when I need something else clarifying I believe that document answers my immediate questions.

Thanks again.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 29, 2009 5:21 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19335
Location: NE Indiana, USA (NTSC)
I've worked with the GBA sound hardware; that's close enough to that of the Game Boy. You might want to try asking on forum.gbadev.org; there are probably still some people left who haven't moved on completely to the DS and remember what "01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10" in wave RAM means. (It's what you write to get the same waveform as the NES triangle wave channel.)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 1:07 am 
Offline

Joined: Wed Apr 22, 2009 12:47 am
Posts: 9
Thanks for the reply.

I've had a stab at the wave pattern channel after reading that doc. It isnt sounding right so im unsure if it is a bug in my code or a misunderstanding with how the wave channel works.

This is the algorithm I use for calculating the wave.

Code:

int CalculateWave ( int numCycles )
{
// dac power, master on off and length counter (if length counter is enabled)
if (channelIsNotEnabled)
 return 0;

bool timeToUpdate = frequency <= numCycles ;
frequency -= numCycles ;

if (timeToUpdate)
{
// reset the frequency
int value = (set5 << 8) | set4 ;
value &= 0x7FF ;
frequency = (2048 - value) * 2 ;

// move on to next wave pos
wavePos++ ;
wavePos = wavePos % 32 ;
}

int volumeControl = set3 >> 5;
volumeControl &= 3;

int shift = 0 ;
switch(volumeControl)
{
case 0: shift = 4 ; break ;
case 1: shift = 0 ; break ;
case 2: shift = 1 ; break ;
case 3: shift = 2 ; break ;
}

return GetDACOutput (wave[wavePos] >> shift)
}



This is just pretty much pseudo code of what im doing. Basically it decreases the frequency by the num of clock cycles the last opcode took. If the frequency becomes less than 0 then it reloads the frequency and moves onto the next wave pos.

The input value given to the DAC is the current sample shifted by the volume control.

This is what the GetDACOutput does

Code:
int GetDACOutput(int volume)
{
   static double analog[] = { -1, -0.8667, -0.7334, -0.6, -0.4668, -0.3335, -0.2, -0.067, 0.0664, 0.2, 0.333, 0.4668,0.6,0.7334,0.8667,1  } ;
   return static_cast<int>(8000 * analog[volume] ) ;
}   


The reason why im doing 8000 multiply the analog value is because SDL is using AUDIO_S16SYS which gives a range of approx -32000 to 32000 and as there are 4 channels 8000 will fit in range.

Also just to confirm something with the other square wave channels, if the current polarity is 0 then it always returns a value of 0, correct? However if the value is 1 then it passes its current volume into GetDACOutput which will return -1 to 1?

Thanks for any help


Last edited by Cloudy on Thu Apr 30, 2009 11:40 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 7:42 am 
Offline
User avatar

Joined: Sun Jun 05, 2005 2:04 pm
Posts: 2142
Location: Minneapolis, Minnesota, United States
tepples wrote:
You might want to try asking on forum.gbadev.org; there are probably still some people left who haven't moved on completely to the DS and remember what "01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10" in wave RAM means. (It's what you write to get the same waveform as the NES triangle wave channel.)


That makes sense. The waveform looks like:

Code:
F |               **
E |              *  *
D |             *    *
C |            *      *
B |           *        *
A |          *          *
9 |         *            *
8 |        *              *
7 |       *                *
6 |      *                  *
5 |     *                    *
4 |    *                      *
3 |   *                        *
2 |  *                          *
1 | *                            *
0 |*                              *
  *--------------------------------


And each 4 bits represents an entry. That's definitely a triangle wave. But it seems like it would be slightly off, as it repeats the wave, playing volume 0 twice.

I think this is how the GB's wave engine works, too. I know it uses 4-bit samples with 16 bytes of RAM to do it with.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 8:12 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19335
Location: NE Indiana, USA (NTSC)
It plays the entry with level 0 twice, and it also plays the entry with level 15 twice. But it's still triangular enough that it sounds like a triangle wave. And each of the 32 steps is flat, which gives the characteristic aliasing at 31f and 33f that defines part of the "NES sound".


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 1:12 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Cloudy wrote:
This is just pretty much pseudo code of what im doing.

Well, I see problems with it, but I'm not sure it's what your real code does. Do you want to get your pseudo-code working, or the real code?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 1:26 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7314
Location: Chexbres, VD, Switzerland
Quote:
And each 4 bits represents an entry. That's definitely a triangle wave. But it seems like it would be slightly off, as it repeats the wave, playing volume 0 twice.

I'm pretty sure the same happens on the NES : The output to the DAC is the low 4 bits each XNORED with the 5th bit of a 5 bit counter. This effectively resulting the 0, 1, ...., 14, 15, 15, 14, ...., 1, 0, 0, 1, .... sequence.

Yet, I guess it doesn't sound the exact same as triangle wave on the NES. Very probably this is due to analog filtering past the DAC, that most emulators/music players emulate (I guess).[/list]

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 4:36 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3968
Is it the step aliasing as it increments in 16 steps that causes the "NES Sound", or is it the doubling of the numbers at the top and bottom of the wave?

Edit:
I just generated two wave files, one using 16 step aliasing, and one using 17 step aliasing (so that the second half goes 16...1 instead of 15...0). Couldn't tell them apart very well listening to them side by side.

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 30, 2009 11:47 pm 
Offline

Joined: Wed Apr 22, 2009 12:47 am
Posts: 9
Thanks for the reply Blarrg.

I have edited my above code to show exactly what I am doing in my real code. The only difference is that my code belongs inside a wave channel class and the CalculateWave is a member of that class a long with the variables "frequency", "wavePos", "wave" and the sets "set3/4/5". I believe that link to the sound development you posted indexes the channel registers (sets) from 0 where I index them from 1 (this is because this is how lord nightmare indexed them and I read his document first).

The boolean "channelNotEnabled" is set to true if the DAC power is off, or the master control is off or the length counter is 0 (including if the length counter is enabled).

So if you can spot any problems im sure they are problems in my actual code.

My second question is when square waves output a polarity of 1 then i feed this to the DAC along with its volume in the same manner as I do with the wave channel to get its analog value. However if the square wave outputs a polarity of 0 then do i just return 0 instead of going though the DAC?

Thanks for any help.

Edit:

I should probably clarify that my actual wave memory is 32 bytes not 16. This is because I find it easier to treat the 2 samples encoded into one byte as two different indexes in the wave memory.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 01, 2009 3:33 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
How are you spreading the 16 wave RAM bytes into your 32-entry wave table? What happens when numCycles is great enough that more than one wave step should occur? Seems you need a while loop. Otherwise, the code looks correct.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 04, 2009 11:49 pm 
Offline

Joined: Wed Apr 22, 2009 12:47 am
Posts: 9
Thanks for the reply. I havent been able to reply over the weekend as I have no internet access. I managed to get some progress over the weekend and now you can clearly hear the correct melody being played in all games which is very encouraging. I feel it is still a long way off being finished though because it sounds awful. Interestingly if I disable all but one of the 4 channels and play it then im convinced I can hear the same channel being played on the real gameboy. So it is like individually they are playing correct but when combined although you can hear each channel is still playing correctly it sounds awful. This is probably because I still have the mixer to emulate. I havent done this yet as I dont know how to use SDL to play a left and right sound buffer. I'll have to look into that.

I wish there was an emulator available that allows you to turn on and off the different channels so you can hear what they individually sound like. I guess that'd really help me see where I am going wrong lol.

Thanks again.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 05, 2009 4:39 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19335
Location: NE Indiana, USA (NTSC)
Cloudy wrote:
I wish there was an emulator available that allows you to turn on and off the different channels so you can hear what they individually sound like.

VisualBoyAdvance.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 05, 2009 7:33 am 
Offline

Joined: Wed Apr 22, 2009 12:47 am
Posts: 9
Thanks for that. My sound channels seems fine but raspy in comparison. Im almost there I can feel it :-)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group