Source

maple-stm32-learn / karplus_string_synthesis / karplus_string_synthesis.pde

/*
karplus-strong.pde
guest openmusiclabs 4.3.12
Karplus-Strong string synthesis

http://en.wikipedia.org/wiki/Karplus%E2%80%93Strong_string_synthesis

  Karplus-Strong string synthesis is a method of physical modelling synthesis that
  loops a short waveform through a filtered delay line to simulate the sound of a
  hammered or plucked string or some types of percussion. Although it is useful to
  view this as a subtractive synthesis technique based on a feedback loop similar
  to that of a comb filter for z-transform analysis, it is better viewed as the
  simplest of a class of wavetable-modification algorithms now known as digital
  waveguide synthesis, as the delay line acts to store one period of the signal.
  Alexander Strong invented the algorithm, and Kevin Karplus did the first analysis
  of how it worked. Together they developed software and hardware implementations
  of the algorithm, including a custom VLSI chip. They named the algorithm
  "Digitar" synthesis, as an abbreviation for "digital guitar".

*/


// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1Khz
#define ADCS 1 // this is checked in AudioCodec_Maple.h, to determine how ADCs are being used

// include necessary libraries
// #include <Wire.h>
// #include <SPI.h>
#include <AudioCodec_Maple.h>

// create data variables for audio transfer
int16 left_in = 0x0000;
int16 left_out = 0x0000;
int16 right_in = 0x0000;
int16 right_out = 0x0000;
int16 last_value = 0x0000;
int16 curr_value = 0x0000;
unsigned int decay = 0x0000;
#define DECAY 65000

uint16 mod0_value =0;

// create a delay buffer in memory
#define SIZE 1600 // buffer size is limited by microcontroller SRAM size
int16 delaymem[SIZE]; // 800 positions x 2 bytes = 1600 bytes of SRAM
uint16 location = 0; // buffer location to read/write from
uint16 boundary = SIZE; 


void seed_delayline()
{
  for (int i = 0; i < SIZE; i++) {
    delaymem[i] = random(65535);
  }

}

void setup() {
  SerialUSB.end();  
  seed_delayline();
  AudioCodec_init(); // setup codec registers
  // call this last if setting up other parts
}

void loop() {
  while (1); // reduces clock jitter
}

// timer1 interrupt routine - all data processed here
// ISR(TIMER1_COMPA_vect, ISR_NAKED) { // dont store any registers
void AudioCodec_interrupt() // use this for Maple vs ISR for arduino
{

  // &'s are necessary on data_in variables
  AudioCodec_data(&left_in, &right_in, left_out, right_out);
  
  // & is required before adc variable
  AudioCodec_ADC(&mod0_value);
  
  if (decay++ < DECAY) {
  
    delaymem[location++] = left_out;
    // check if location has gotten bigger than buffer size
    if (location >= boundary) {
      location = 0; // reset location
    }
    curr_value = delaymem[location];
    left_out = (last_value>>1) + (curr_value>>1);
    last_value = curr_value;
  }
  else {
    for (int i = 0; i < SIZE; i++) {
      delaymem[i] = random(65535);
    }
    decay = 0;
    
    unsigned int scale = SIZE;

    // I suspect this is originally from Arduino specialized 16bit x 16bit multiplication
    // which returns a 16 bit number
    // MultiU16X16toH16(boundary, mod0_value, scale);
    boundary = (mod0_value * scale) >> 16;
  }
  // dont forget to return from interrupt
  // may not need this on maple
  // reti();
}