General question about the Code
Closed this issue ยท 2 comments
Hello Nathan,
Fist of all thank you for the work you've done on that library :)
I am working on waveform generation using PWM with the arduino UNO and I have questions regarding some parts of the code:
- I can't understand how the mixer part takes care of the dynamic of different voices. How can the overall signal is not saturating ? I dont get this line in particular:
shared+=((((signed char)pgm_read_byte(wavs[i] + ((unsigned char *)&(PCW[i] += FTW[i]))[1]) * AMP[i]) >> 8) >> 2);
- I would like to generate the same output(SIN mode, pitch , env, vol ) but in quadrture phase on the other Channel. To do so I would have to shift the value taken from the wave table by 64. Do you think this operation needs an exclusive voice ? Or is there a way to use the same and copy it to both channel ?
Thanks for your help !
Hi Peouse,
Thank you for using my library ๐. Sorry I responded late. Github didn't email me for some reason.
Anyways, let's answer those questions.
- Let's anaylze how the code mixes the different voices :)
-
Since the Arduino Uno and its atmega328p friends only shares two pins(11 and 3) with Timer 2, I decided to take advantage of stereo mode. I used two variables,
shared
andsample
to output the audio data on two PWM pins. Theses variables' output value have a range from(-127) to 127
, because the mixing of voices will come out as either a negative or positive number based on the wavetables, to fix this, we setsample = 127
,shared = 127
before mixing our instruments, the output value will always be positive, thus making the range0-256
. I believe this code is in aFor loop
so the Arduino adds all the instruments that you intitate to whichever pin in your arduino sketch. -
The second part,
(signed char)pgm_read_byte
This part is where I access the variables fromPROGMEM
. -
The stuff inside the
PROGMEM
, is probably where things get interesting. :)wavs[i]
is a wavetable and the variablei
is the instrument number.- So intrument 1 could have a
SINE
wave, and instrument 2 could have aRAMP
wave.
- So intrument 1 could have a
((unsigned char *)&(PCW[i] += FTW[i]))[1]
This code handles the modulation and the fancy music effects when you use thesetMod(int fancy)
function. I got it from Dzlonline.AMP[i]
is the volume and the sustain effect that you hear in a keyboard/piano.>> 8) >> 2
is the shifting bits part. Mixing voices can be fun, here lies a problem...If you combine too many voices you get saturation ๐. For example, instrument 1 could be playing an output at 127, and instrument 2 plays at 100, and instrument three could be playing at 50. If you add these outputs together, you get127+100+50 = 277, which is greater than 256
๐ข- Bitwise to the rescue!!! To mix voices, you use bitwise operators, so we shift each bit in order for the max to be capped at 256. How do we do that? .... Well,
2^8 = 256
, so all we have to do if shift127>>8 + 100 >>8 + 50 >>8 = something less than 256
. The second bitwise shift is a little harder to explain, since we are in afor loop
, if i don't shift to the right it doesn't work ยฏ\(ใ)/ยฏ, but shifting to the right 2 bits works just fine. ๐
- Bitwise to the rescue!!! To mix voices, you use bitwise operators, so we shift each bit in order for the max to be capped at 256. How do we do that? .... Well,
-
Also the maxVolume needs to be limited otherwise the the arduino will make a loud crackling sound; I fixed that issue with this code.
- I'm not sure what quadrture sounds like, but I think I kinda get what you want. You can simple set
shared+=sample/64
, and avoid mixing voices forshared
sincesample
will do that for you. So maybe something like this??
for (uint8_t i = 0; i < numVoice; i++) {
if(stereoMode[i]==0){
sample+=((((signed char)pgm_read_byte(wavs[i] + ((unsigned char *)&(PCW[i] += FTW[i]))[1]) * AMP[i]) >> 8) >> 2);
shared +=sample/64;//quadrture
}
else{
//shared+=((((signed char)pgm_read_byte(wavs[i] + ((unsigned char *)&(PCW[i] += FTW[i]))[1]) * AMP[i]) >> 8) >> 2);
}
}
Hello Nathan,
-
Thank you for this ! I think I have my answer. I was confused between the shift operation that handles PWM output and the volume limiting which is done separately. Still a bit confusing how everything mixes up just fine though ^^.
-
I will try your suggestion see if it does what I want. Actually quadrature phase will 'sound' the same, but I want to plot a signal upon the other with the oscilloscope.
Theoretically that would give me circle ๐
Thanks again for your help !