Trouble Assigning a Gain to my amplitude modulation

int updateAudio(){
  int32_t mod = (128u+ (int32_t)aModul.next()) * ((byte)128+ (int32_t)aModDepth.next());
  int32_t out = (mod * (int32_t)aCar.next())>>16;
  return (int)out;

I am trying to assign this amplitude modulation to a pot so that I can turn the amplitude up and down. However, when I multiply the return by my assigned pot, it starts to distort. I understand that it is due to my bit shift being wrong, and my modulator (aModul) needs to be halved in amplitude, but I am having trouble doing it. Any pointers?

Try this:

// Variable AM modulate sample - 0 to 100% AM modulation
// passed:
//    sample      sample (uint8_t) of the waveform to be modulated 
//    amSample    sample (uint8_t) of the modulating waveform
//    depth       depth (int) of modulation, 0= 100% original, 255=100% modulated
// returns:
//    modulated sample
//
#define VAM_MODULATE( sample, amSample, depth )  ((uint8_t)(((  ((int)(sample)-127) * ((((uint16_t)(amSample) * (uint16_t)(depth)) >> 8) + (255-(depth)))  ) >> 8) + 127))

Note that the 8-bit samples are unsigned.

Yours,
TonyWilk

didn't work sorry, but thanks for the recommendation. Just increased the freq of the AM then the same distortion occurred one I added

gain= 2;

return out * gain;

Gilmour928:
didn't work sorry, but thanks for the recommendation.

So have you fixed your problem ?

If not... you need to post your whole code.

Trying to guess what your code is doing and what type your variables are means that we can, at best, give 'trying to guess' answers.

Yours,
TonyWilk

I haven’t solved it yet. Sorry still a noob haha. Here it is:

#include <MozziGuts.h> // including the mozzi library into the script
#include <Oscil.h> // oscillator template
#include <tables/saw2048_int8.h> // saw wave table for oscillator
#include <mozzi_midi.h>
#include <mozzi_fixmath.h>
#include <mozzi_rand.h>
#include <mozzi_utils.h>
#include <tables/chum9_int8.h> // 
#include <LowPassFilter.h>

#define CONTROL_RATE 64

// audio ocillator
Oscil<SAW2048_NUM_CELLS, AUDIO_RATE> aCar(SAW2048_DATA); // AM carrier / saw oscillator
Oscil<SAW2048_NUM_CELLS, AUDIO_RATE> aModul(SAW2048_DATA); // AM modulator oscillator
Oscil<SAW2048_NUM_CELLS, AUDIO_RATE> aModDepth(SAW2048_DATA); // AM mod depth
Oscil<CHUM9_NUM_CELLS, AUDIO_RATE> aLPF(CHUM9_DATA); // lpf oscillator


int fader = A4;
int LDR = A3;
int ledgreen = 3;
int muteswitch = 2;
int gain = A5;
int button = 12;

int mute = 0;
int midi = 0;
Q8n8 ratio;
Q24n8 carrierfreq;
Q24n8 modfreq;
LowPassFilter lpf;

void setup() {
 
 Serial.begin(31250); //31250 rate used because midi cant handle any higher
 pinMode (ledgreen, OUTPUT);

 startMozzi(CONTROL_RATE); // control rate of 64
 
 ratio = float_to_Q8n8(3.0f); 
 aModDepth.setFreq(13.f);
 randSeed();

}

void updateControl(){
 {
  LDR = mozziAnalogRead(A3); //LDR funtion controls phasor in opto coupler
  gain = mozziAnalogRead(A5); // gain function controls amplitude of second fader in A3
  fader = mozziAnalogRead(A4); // fader will control frequency when button not pressed
 }
 
 {
  static Q16n16 lastnote = LDR;

  if(rand((byte)5)==0){
      lastnote = 36+(rand((byte)6)*12);
    }

    // change step up or down a semitone occasionally
    if(rand((byte)13)==0){
      lastnote += 1-rand((byte)3);
    }

    // change modulation ratio now and then
    if(rand((byte)5)==0){
      ratio = ((Q8n8) 1+ rand((byte)5)) <<8;
    }

    // sometimes add a fractionto the ratio
    if(rand((byte)5)==0){
      ratio += rand((byte)255);
    }

    // step up or down 3 semitones (or 0)
    lastnote += 3 * (1-rand((byte)3));

    // convert midi to frequency
    Q16n16 midinote = Q8n0_to_Q16n16(lastnote); 
    carrierfreq = Q16n16_to_Q24n8(Q16n16_mtof(midinote));

    // calculate modulation frequency to stay in ratio with carrier
    modfreq = (carrierfreq * ratio)>>8; // (Q24n8   Q8n8) >> 8 = Q24n8

      // set frequencies of the oscillators
    aCar.setFreq_Q24n8(carrierfreq);
    aModul.setFreq_Q24n8(modfreq);
 }
}

int updateAudio(){
  
    int32_t mod = (128u+ (int32_t)aModul.next()) * ((byte)128+ (int32_t)aModDepth.next());
    float out = (mod * aCar.next())>>16;
    return (int)out;
}

void loop() {

 audioHook();
 
 
  mute = digitalRead(muteswitch); // assigning mute variable to muteswitch in pin 2
  midi = digitalRead(button); // assigning midi variable to button

  if (mute == 1 && midi == 0) // when switch in in on (1) position, sound and light both function.

  {
    int mappingfreq = LDR;
    mappingfreq = map(mappingfreq, 0, 1023, 200,4000); 
    aCar.setFreq(mappingfreq);
    
    analogWrite(ledgreen, gain>>2); // bit shift used to map 255 positions of led to 1023 of fader 
    
  }

  if (mute == 1 && midi == 1)
  {
    
    int lightfade = 10; // light on/off no longer visible at 10ms
    int note = analogRead(fader) / 8;  
    noteOn(0x90, note, 0x45); // 0x90 means note on, on channel 0 in hexadecimal
    noteOn(0x80, note, 0x00); // 0x80 means note off on channel 0 in hexadecimal 
  
    Serial.println("");
  }

  else if (mute == 0 && midi == 0) // when switch is in off (0) position, no sound, no light. 

  {
    
    gain = 0; 
    digitalWrite(ledgreen, LOW);
  }
 
 
}
 void noteOn(int cmd, int pitch, int velocity) {
   Serial.write(cmd);
   Serial.write(pitch);
   Serial.write(velocity);
 }

There are other errors still in there, I was just trying to solve the problem with the gain first.

Ah, looks like your program is using SIGNED 8-bit sample values

int8_t AM_modulate( int8_t carrier, int8_t modulation, int8_t depth )
{
  int16_t sample= (int16_t)carrier;         // carrier is signed
  uint16_t am= (uint16_t)( (int16_t)modulation + 128 );   // unsigned modulation 0..255
  uint16_t dp= (uint16_t)( (int16_t)depth + 128 );        // unsigned depth 0..255
 
  return (int8_t)( (sample * (((am * dp) >> 8) + (255 - dp))) >> 8 ); 
}

Unlike my previous VAM_MODULATE macro (which is out of my working synth code), the above code is completely untested but based on the same calculation.

Yours,
TonyWilk

Still not working as I would hope sorry. The amplitude modulation works great, and although it is not distorting like before, it is not controlling the volume as I'd expect. In fact, seems louder when gain = 0. Here is the code with my gain added:

int updateAudio(){
  
    int8_t AM_modulate( int8_t carrier, int8_t modulation, int8_t depth );

  int16_t sample= (int16_t)carrier;         // carrier is signed
  uint16_t am= (uint16_t)( (int16_t)modulation + 128 );   // unsigned modulation 0..255
  uint16_t dp= (uint16_t)( (int16_t)depth + 128 );        // unsigned depth 0..255
 
  return (int8_t)( (sample * (((am * dp) >> 8) + (255 - dp))) >> 8 ) * gain;

Gilmour928:
Still not working as I would hope sorry. The amplitude modulation works great, and although it is not distorting like before, it is not controlling the volume as I'd expect.

Er, not sure what you mean there.
Amplitude Modulation will not alter the overall "volume" as such.

If your AM modulation was at 2Hz, 100%l depth, then you would hear the 'carrier' simply rise and fall in volume.

If your AM modulation is 50Hz, 100% depth, then the volume you hear will not be 'half volume'

In any case, it looked like other bits of your code were using some waveform for the carrier and for the AM modulation and for the depth. ?

A simple use of AM would be to, say, have a carrier of 1000Hz, AM modulation of 100Hz and a fixed depth of 50%. Here's a pic from the wikipedia article on Amplitude modulation

If you want to change the overall volume... that's a different thing.

If you have a volume variable from 0 to 255, then this should set the volume of a signed 8-bit sample:

int8_t newsample= (int8_t)( ((int16_t)sample * (int16_t)volume) >> 8 );

Yours,
TonyWilk

That’s worked cheers!