Tag Archives: lfo

LFO modulated simple VCF

lfo_vcf_rev_aa001

this is a rough draft of a circuit i’ve been working on based of the Simple VCF circuit floating out there. a big thanks to the original author for that. i’m sure there are some mistakes in here. it’s an odd one for sure, but it works on the breadboard. the opamp is a TL072. square-wave input from the generator comes out pretty sine-wave like which is what is desired. the output is a little noisy, but i will work that out with time.

initial test of a modulated PT2399 circuit…

a breadboard version of some PT2399 modifications i’ve been working on. there are a lot of DIY schematics that utilize the PT2399 (Magnus Modulus, Echo Base delay, Rebote, etc.). i’ve been interested at trying my hand at modulation techniques recently. i made a simple LFO circuit based on the findings mentioned in a previous post. i used some techniques out lined in some of the schematics floating out there to attempt to modulate the delay time of the chip. i wouldn’t say i’ve got it to work perfectly, but it’s definitely doing what i had hoped.

simple LFO circuits…

i was reading over this thread on diystompboxes.com about building an analog LFO circuit for some wild noise idea i’ve got brewing in the back of my head. i started messing around with some of the schematics on there and got a drifting saw wave out of it after a while. i was trying to take a picture of the wave itself on the oscilloscope which obviously didn’t turn out all that well. so many breadboards. yeesh.

Arduino: LFO Generator

here’s a treat for anyone that’s into the audio side of arduino. it’s an 8-bit two-timer based LFO Generator using timer 0/2 on an ATMega328p. i’m only using timer0 for output in this code. i’ve started implementing the LFO code into my 8-bit melotronium where timer2 is dedicated for the audio output. in the larger code base, timer0 just stores values in an unsigned integer that the other timer grabs and modulates the output mathematically. for now, this should be a good reference to anyone looking for the outline of an LFO with seven different wave forms.

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

uint8_t sineTable[] = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,
  192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,
  239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,
  254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,
  233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,
  181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,
  115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,
  42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,
  0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31, 33,35,37,39,42,
  44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
};

uint8_t tWave = 128;
uint8_t sWave = 255;
uint8_t ruWave = 128;
uint8_t rdWave = 128;
uint8_t rWave = 128;

int   i = 0;
int   rate;
int   waveform;
byte  d = HIGH;

void setup() {
  pinMode(3, OUTPUT);
  setupTimer();
  OCR0A = 128;
}

void loop() {
  waveform = map(analogRead(0),0,1023,1,7);
  rate = map(analogRead(1),0,1023,255,0);
  OCR0A = rate;
}

ISR(TIMER0_COMPA_vect) {
  if(i == 255) i = 0;
  switch(waveform) {
    case 1:
      analogWrite(3,sine(i));
    break;
    case 2:
      analogWrite(3,triangle(i));
    break;
    case 3:
      analogWrite(3, square(i));
    break;
    case 4:
      analogWrite(3, rampUp(i));
    break;
    case 5:
      analogWrite(3, rampDown(i));
    break;
    case 6:
      analogWrite(3, rand(i));
    break;
    case 7:
      analogWrite(3, white(i));
    break;
  }
  i++;
}

void setupTimer() {
  cli();
/*--- TIMER2 CONFIG ---*/
  sbi(TCCR2A,WGM20);
  sbi(TCCR2A,WGM21);
  cbi(TCCR2A,WGM22);
 
  sbi(TCCR2B, CS20);
  cbi(TCCR2B, CS21);
  cbi(TCCR2B, CS22);

  sbi(TCCR2A,COM2B1);
  cbi(TCCR2A,COM2B0);
   
 /*--- TIMER0 CONFIG ---*/ 
  cbi(TCCR0B,CS00);
  cbi(TCCR0B,CS01);
  sbi(TCCR0B,CS02);
 
  sbi(TCCR0A, COM0A1);
  cbi(TCCR0A, COM0A0);
    
  cbi(TCCR0A, WGM00);
  sbi(TCCR0A, WGM01);
  cbi(TCCR0A, WGM02);

  cbi(TIFR0,OCF0A);
  sbi(TIMSK0,OCIE0A);
  sei(); 
}

int sine(int i) {
  return sineTable[i];
}

int triangle(int i) {
  if(tWave >= 255) d = LOW;
  if(tWave <= 0) d = HIGH;
  if(d == HIGH) tWave++;
  if(d == LOW) tWave--;
  return tWave; 
}

int rampUp(int i) {
  ruWave++;
  if(ruWave > 255) ruWave = 0; 
  return ruWave;
}

int rampDown(int i) {
  rdWave--;
  if(rdWave < 0) rdWave = 255;
  return rdWave;
}

int square(int i) {
  if(i >= 128) sWave = 255;
  if(i <= 127) sWave = 0;
  return sWave;
}

int rand(int i) {
  if(i == rWave) rWave = random(255);
  return rWave;
}

int white(int i) {
  return random(255);
}

Update: Here's my current code for the ATTiny85. It's not exactly bug-free as there seems to be some issue with latch-up when the speed of the LFO is high. This of course could be remedied by limiting the map() function's minimum value. I can't remember off hand if there are any other issues. Good power supply and output filtering is definitely needed to reduce noise in any additional stages of the circuit. At some point, I'll just make a separate post detailing my tremolo effect circuit in detail (so many projects and so little time!). Until then:

/*
 * Title: LFO Generator for ATTiny85 v0.12
 * Author: Abram Morphew
 * Date: 09.19.2016
 * Purpose: Low frequency oscillator with wave output controls
 */

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

uint8_t sineTable[] = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,
  192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,
  239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,
  254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,
  233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,
  181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,
  115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,
  42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,
  0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31, 33,35,37,39,42,
  44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
};

uint8_t tWave = 128;
uint8_t sWave = 255;
uint8_t ruWave = 128;
uint8_t rdWave = 128;
uint8_t rWave = 128;

int   i = 0;
int   rate;
int   waveform;
byte  d = HIGH;
const uint8_t output = 1;                       // output pin #6 on ATTiny85

void setup() {
  setupTimer();
  pinMode(3, INPUT);
  pinMode(2, INPUT);
  pinMode(output, OUTPUT);
  OCR0A = 128;
}

void loop() {
  waveform = map(analogRead(2),0,1023,1,6);
  rate = map(analogRead(3),0,1023,255,0);
  OCR0A = rate;
}

ISR(TIMER0_COMPA_vect) {
  if(i == 255) i = 0;
  switch(waveform) {
    case 1:
      analogWrite(output,sine(i));
    break;
    case 2:
      analogWrite(output,triangle(i));
    break;
    case 3:
      analogWrite(output, square(i));
    break;
    case 4:
      analogWrite(output, rampUp(i));
    break;
    case 5:
      analogWrite(output, rampDown(i));
    break;
    case 6:
      analogWrite(output, rand(i));
    break;
    case 7:
      analogWrite(output, white(i));
    break;
  }
  i++;
}

void setupTimer() {
  cli(); 
 /*--- TIMER0 CONFIG ---*/  
  TCCR0A = 0b10000011;
  TCCR0B = 0b00001010;    // last 3 bits set prescalar for Timer0

  cbi(TIFR,OCF0A);
  sbi(TIMSK,OCIE0A);
  sei(); 
}

int sine(int i) {
  return sineTable[i];
}

int triangle(int i) {
  if(tWave >= 255) d = LOW;
  if(tWave <= 0) d = HIGH;
  if(d == HIGH) tWave++;
  if(d == LOW) tWave--;
  return tWave; 
}

int rampUp(int i) {
  ruWave++;
  if(ruWave > 255) ruWave = 0; 
  return ruWave;
}

int rampDown(int i) {
  rdWave--;
  if(rdWave < 0) rdWave = 255;
  return rdWave;
}

int square(int i) {
  if(i >= 128) sWave = 255;
  if(i <= 127) sWave = 0;
  return sWave;
}

int rand(int i) {
  if(i == rWave) rWave = random(255);
  return rWave;
}

int white(int i) {
  return random(255);
}