nathanRamaNoodles/Noodle-Synth

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:

  1. 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);

  1. 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.

  1. 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 and sample 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 set sample = 127, shared = 127 before mixing our instruments, the output value will always be positive, thus making the range 0-256. I believe this code is in a For 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 from PROGMEM.

    • The stuff inside the PROGMEM, is probably where things get interesting. :)

      • wavs[i] is a wavetable and the variable i is the instrument number.
        • So intrument 1 could have a SINE wave, and instrument 2 could have a RAMP wave.
      • ((unsigned char *)&(PCW[i] += FTW[i]))[1] This code handles the modulation and the fancy music effects when you use the setMod(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 get 127+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 shift 127>>8 + 100 >>8 + 50 >>8 = something less than 256. The second bitwise shift is a little harder to explain, since we are in a for loop, if i don't shift to the right it doesn't work ยฏ\(ใƒ„)/ยฏ, but shifting to the right 2 bits works just fine. ๐Ÿ˜„

Also the maxVolume needs to be limited otherwise the the arduino will make a loud crackling sound; I fixed that issue with this code.

  1. 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 for shared since sample 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 !