GP32 Frequency Generator And Mixing


Rattboi

Certified Guru
Joined
Mar 8, 2003
Messages
132
Age
40
I'm not very knowledgable about how sound works or how to program sound.
I'm wondering how you would make 1 channel with a certain frequency.
Then, I'm wondering how you would have > 1 channel and mix them properly.

Could someone give me a few ideas how this works, preferably with a little code or pseudocode.

I'm using GP SDK also, but I'm sure I could figure it out no matter the SDK.
 
I'm no expert, I can only tell you what happens in the emulator sources I've seen.

All that happens for multiple channels, is the sound is sampled on each of the channels. Then each of the samples from each channel are added together to form the actual sound sample that goes in gp32 sound buffer.
 
Yeah,

From what I understand, basic mixing is just adding up the channel values, and averaging them.

So (Sum(Channel Values))/Num Channels is basic mixing, I think

I don't know how to make a frequency into samples though
 
First, you need to reserve some memory sor storing you sound data. The amount of memory to reserve depends on sampling rate, bit rate and of course length of the sample. The common value for sampling rate is 44100 and for bit rate it's 16. Suppose we want to have 5 seconds of sound, then we will need (5 * 44100 * 2 * 2) byte of memory. The first 2 is for the 16 bit (=2 byte) bit rate. The second 2 is for the two channels since we have stereo.

Code:
unsigned short wav_data[5*44100*2] = {0};

Sine we use unsigned short here, which is a 2 byte integer type, we can skip the first 2 when giving the array size.

The sound initialization then has to be done with:

Code:
 GpPcmInit(PCM_S44, PCM_16BIT);

To fill the buffer with a wave of a certain frequency, you have to choose the waveform first. There are numerous basic waves like sine, square, sawtooth or triangle. You can find several examples on the net on how to create these. This way, you fill your buffer.

To mix two buffers, you just add them together, value by value. If the resulting value is too high for 16 bit, then clamp it, i.e. set it to the maximum value, or else you will hear ugly cracking overruns. What you shouldn't do is divide the result by the number of channels. That is a common misbelief.

I hope this helps you.
 
So (Sum(Channel Values))/Num Channels is basic mixing, I think

no - there is no divide - just add the channels, simple really. Also you've got to clip the result else you'll get really really horrible distortion.
 
So say I was doing 8bit samples.
I'd want to make sure that it'd never go over 128 or under -127 because that's where it'd wrap and that's what causes the horrible distortion, correct?

Ok, so back to the "frequency generator" thing. It's more like, if I have a bunch of samples, and I want to play them at a certain frequency, how do I do that? Keep in mind that this is multiple channels.

Maybe I should look at a mod player source...

Thanks for the feedback so far :)
 
So say I was doing 8bit samples.
I'd want to make sure that it'd never go over 128 or under -127 because that's where it'd wrap and that's what causes the horrible distortion, correct?


yup - that wrapping would cause terrible distortion, so you've gotta clip to -127,128 - you still get distortion - but no where near as bad. If fact when writing your tune e.t.c. you adjust the levels of each track so it doesnt clip.

Frequency generation - it all depends on your hardware sample rate, so say you hardware is outputing at 44khz the highest frequency that you can output is 22khz (which would be a cycle length of two samples). you're best bet is to have a look at some src code it's all quite easy stuff.
 
Whoa,

Quick reply!

About the frequency stuff, I'm trying to get sound working in Wonderboi. The Wonderboi has 4 sound channels, each that can play short samples at different frequencies.

The original code is using directsound, and making each channel and just doing:

channel->SetFrequency(freq);

I don't know exactly how I'd map that to GP32 sound stuff, so that's where I am, really.
 
>>Whoa,

>>Quick reply!

I'm at work and bored waiting for a build :(

>>The original code is using directsound, and making each channel and just doing:

>>channel->SetFrequency(freq);

>>I don't know exactly how I'd map that to GP32 sound stuff, so that's where I >>am, really.


umm you've got 2 choices

1) Writing your own software mixer, mix all the channels into 1 and output your mixed channel to hardware - I think there's some source code to do this (for gp32)

2) I think the gp32 hardware can mix 4 channels for you? (I may be wrong it's been a long time on the gp32)
 
I feel more comfortable with #1 choice.

I think that what I'm not getting is how the samples and the frequency are related.
If I'm outputing at 22kH, and my channel is 4kH frequency, does that mean I use the same place in the sample (22/4) times before going to the next place in the sample?

Basically, is the ratio of gp32 to channel frequency the step increase of the sample data?

I wish I could be more clear, but my vocabulary with this stuff is limited at best.
 
I doubt it, as 44kHz sound is better then 22kHz... I believe this is the samplerate, so at 22kHz, 22 000 samples are taken every second, this has nothing to do with the actualy frequency of the sound being output however.
 
That's what I'm saying (I think)

if you think in terms of input and output, it's like this...

GP32 = Output = 22 kHz
Wonderswan channel = Input = variable kHz (let's say 5 kHz)

So since the GP32 is sampling faster than the Wonderswan is, you'd use the same sample (22 / 5) times before going on to the next sample. Is this correct?
 
Yup! That's exactly it!

Don't use 22 div 5 though ;)

You can use something like ...
Initializing
Code:
GP32freq=22
Swanfreq=5

samplepos=0
samplecounter=GP32freq/2
then for every GP32 sample slot (or in a loop to fill a buffer)
Code:
samplecounter=samplecounter-Swanfreq
if(samplecounter<0)
{
 samplecounter=samplecounter+GP32freq
 samplepos=samplepos+1
}
play(samplepos)
 
the best way to do this is to use fixedpoint maths:



int SamplePos=0;
int SampleSpeed;

SampleSpeed=65535*2; // Would play the sample at double it's original freq
SampleSpeed=65535; // would play the sample at is original freq
SampleSpeed=32768; // would play the sample at 1/2 is original freq

in your loop - you'd have somehing like this:


CurrentSample=Samples[SamplePos>>16];
SamplePos+=SampleSpeed;
 
Ah, I think I get it

Lemme hack around with that for a while
 
Back
Top