replace mod1_value with serial input from MAX MSP

replace mod1_value with serial input from MAX MSP

Postby instantplaces » Thu Aug 16, 2012 7:16 am

I'd appreciate some pointers to alter the sine_generator example so that mod1_value is sent from a Max MSP patch using the serial object in Max and Serial.read in Arduino. I suspect my lack of success has to do with
" // use upper byte of mod1 value to set the rate ".

I put Serial.begin(9600); in the setup

and trying

if (Serial.available() > 0)
{
// read the oldest byte in the serial buffer:
incomingByte = Serial.read();
mod1_value = (incomingByte * 4);

}

as an attempt to replace mod1_value with the incoming serial values.

The Max patch is basically the Dimmer example in Arduino:
http://arduino.cc/en/Tutorial/Dimmer

sketch

=====

/*
sine_generator.pde
guest openmusiclabs 7.7.11
this program creates a sinewave of variable frequency and
amplitude, presented at both left and right outputs. there
isnt any interpolation, so you only get 256 discrete frequencies
across the span of 44Hz to 10kHz.
*/

// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1kHz sample rate
#define ADCS 2 // use both ADCs

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

// create data variables for audio transfer
// even though there is no input needed, the codec requires stereo data
int left_in = 0; // in from codec (LINE_IN)
int right_in = 0;
int left_out = 0; // out to codec (HP_OUT)
int right_out = 0;

int incomingByte = 100;

// create variables for ADC results
// it only has positive values -> unsigned
unsigned int mod0_value = 0;
unsigned int mod1_value = 0;

// create sinewave lookup table
// PROGMEM stores the values in the program memory
// it is automatically included with AudioCodec.h
PROGMEM prog_int16_t sinewave[] = {
// this file is stored in AudioCodec.h and is a 1024 value
// sinewave lookup table of signed 16bit integers
// you can replace it with your own waveform if you like
#include <sinetable.inc>
};
unsigned int location; // lookup table value location







void setup() {
// call this last if you are setting up other things
AudioCodec_init(); // setup codec and microcontroller registers
Serial.begin(9600);
}

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

if (Serial.available() > 0)
{
// read the oldest byte in the serial buffer:
incomingByte = Serial.read();
mod1_value = (incomingByte * 4);

}


}



// timer1 interrupt routine - all data processed here
ISR(TIMER1_COMPA_vect, ISR_NAKED) { // dont store any registers

// &'s are necessary on data_in variables
AudioCodec_data(&left_in, &right_in, left_out, right_out);

// create some temporary variables
// these tend to work faster than using the main data variables
// as they arent fetched and stored all the time
int temp1;
int temp2;

// create a variable frequency and amplitude sinewave
// fetch a sample from the lookup table
temp1 = pgm_read_word_near(sinewave + location);
// step through table at rate determined by mod1
// use upper byte of mod1 value to set the rate
// and have an offset of 1 so there is always an increment.
location += 1 + (mod1_value >> 8);
// if weve gone over the table boundary -> loop back
// around to the other side.
location &= 0x03ff; // fast way of doing rollover for 2^n numbers
// otherwise it would look like this:
// if (location >= 1024) {
// location -= 1024;
// }

// set amplitude with mod0
// multiply our sinewave by the mod0 value
MultiSU16X16toH16(temp2, temp1, mod0_value);
// our sinewave is now in temp2
left_out = temp2; // put sinusoid out on left channel
right_out = -temp2; // put inverted version out on right chanel

// get ADC values
// & is required before adc variables
AudioCodec_ADC(&mod0_value, &mod1_value);



reti(); // dont forget to return from the interrupt
}

=====
instantplaces
 
Posts: 6
Joined: Mon Aug 13, 2012 3:27 pm

Re: replace mod1_value with serial input from MAX MSP

Postby guest » Thu Aug 16, 2012 8:16 am

this sounds awesome
here is some code that works

but first, redownload the libraries from the wiki
i found a mistake in the header files a few days ago
and rewrote them
it wouldnt make much difference for your code
but might for some future code
basically i wasnt storing certain registers during the interrupt
so that could cause problems if anything is put into loop() {}

Code: Select all
/*
sine_generator.pde
guest openmusiclabs 7.7.11
this program creates a sinewave of variable frequency and
amplitude, presented at both left and right outputs. there
isnt any interpolation, so you only get 256 discrete frequencies
across the span of 44Hz to 10kHz.
*/

// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1kHz sample rate
#define ADCS 1 // use both ADCs

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

// create data variables for audio transfer
// even though there is no input needed, the codec requires stereo data
int left_in = 0; // in from codec (LINE_IN)
int right_in = 0;
int left_out = 0; // out to codec (HP_OUT)
int right_out = 0;

// create variables for ADC results
// it only has positive values -> unsigned
unsigned int mod0_value = 0;
unsigned int mod1_value = 0;

// create sinewave lookup table
// PROGMEM stores the values in the program memory
// it is automatically included with AudioCodec.h
PROGMEM  prog_int16_t sinewave[]  = {
  // this file is stored in AudioCodec.h and is a 1024 value
  // sinewave lookup table of signed 16bit integers
  // you can replace it with your own waveform if you like
  #include <sinetable.inc>
};
unsigned int location; // lookup table value location


void setup() {
  Serial.begin(9600);
  // call this last if you are setting up other things
  AudioCodec_init(); // setup codec and microcontroller registers
}

void loop() {
  while (1) {
    if (Serial.available() > 0) {
      // read the oldest byte in the serial buffer:
       mod1_value = Serial.read() << 8;
     }
  }
}

// timer1 interrupt routine - all data processed here
ISR(TIMER1_COMPA_vect) { // changed to store registers (NAKED removed)

  // &'s are necessary on data_in variables
  AudioCodec_data(&left_in, &right_in, left_out, right_out);
 
  // create some temporary variables
  // these tend to work faster than using the main data variables
  // as they arent fetched and stored all the time
  int temp1;
  int temp2;
 
  // create a variable frequency and amplitude sinewave
  // fetch a sample from the lookup table
  temp1 = pgm_read_word_near(sinewave + location);
  // step through table at rate determined by mod1
  // use upper byte of mod1 value to set the rate
  // and have an offset of 1 so there is always an increment.
  location += 1 + (mod1_value >> 8);
  // if weve gone over the table boundary -> loop back
  // around to the other side.
  location &= 0x03ff; // fast way of doing rollover for 2^n numbers
                      // otherwise it would look like this:
                      // if (location >= 1024) {
                      // location -= 1024;
                      // }
 
  // set amplitude with mod0
  // multiply our sinewave by the mod0 value
  MultiSU16X16toH16(temp2, temp1, mod0_value);
  // our sinewave is now in temp2
  left_out = temp2; // put sinusoid out on left channel
  right_out = -temp2; // put inverted version out on right chanel

  // get ADC values
  // & is required before adc variables
  AudioCodec_ADC(&mod0_value);

//  reti(); // reti not included when NAKED is removed
}


a few things to note:
1. get rid of the NAKED in the ISR
2. get rid of the reti() in the ISR
3. get rid of the second, unused mod_value
4. the input byte is upshifted to a 16b value

i tried this with the arduino serial comm and it worked
let me know how it goes
guest
Site Admin
 
Posts: 449
Joined: Thu May 20, 2010 11:58 pm

Re: replace mod1_value with serial input from MAX MSP

Postby instantplaces » Thu Aug 16, 2012 12:58 pm

Thanks for the pointers! Your sine gen sketch works with control from MAX.

Now attempting to alter the tremolo example in similar fashion. Dragging the MAX slider sending 0 to 255 to the altered sketch causes the tremolo speed to change while dragging, but doesn't set a new trem speed.

If I use

mod1_value = Serial.read() >> 8;

the trem slows while dragging, then returns to a default speed.

If I use

mod1_value = Serial.read() << 8;

the trem speeds while dragging, then returns to a default speed.

So, how to have the serial input set a new trem speed?

===========

/*
tremolo.pde
guest openmusiclabs 7.11.11
this program creates a mono tremolo effect by taking input
from the left channel and multiplying it by a low frequency
sinewave. the frequency is set with MOD1, and the depth is
set with MOD0. the amplitude modulated signal is presented
at the right output, and a mix of the wet and dry signals
is presented at the left output.
*/

// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1kHz sample rate
#define ADCS 2 // use both ADCs

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

// create data variables for audio transfer
// even though the function is mono, the codec requires stereo data
int left_in = 0; // in from codec (LINE_IN)
int right_in = 0;
int left_out = 0; // out to codec (HP_OUT)
int right_out = 0;

// create variables for ADC results
// it only has positive values -> unsigned
unsigned int mod0_value = 0;
unsigned int mod1_value = 0;

// create sinewave lookup table
// PROGMEM stores the values in the program memory
// it is automatically included with AudioCodec.h
PROGMEM prog_int16_t sinewave[] = {
// this file is stored in the AudioCodec library and is a
// 1024 value sinewave lookup table of signed 16bit integers.
// you can replace it with your own waveform if you like.
#include <sinetable.inc>
};
// lookup table value location
unsigned long location; // this is a 32bit number
// the lower 8bits are the subsample fraction
// and the upper 24 bits contain the sample number


void setup() {
Serial.begin(9600);
// call this last if you are setting up other things
AudioCodec_init(); // setup codec and microcontroller registers
}

void loop() {
while (1) {
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
mod1_value = Serial.read() << 8;
}
}
}

// timer1 interrupt routine - all data processed here
ISR(TIMER1_COMPA_vect) { // dont store any registers

// &'s are necessary on data_in variables
AudioCodec_data(&left_in, &right_in, left_out, right_out);

// create some temporary variables
unsigned int temp0;
unsigned char frac;
int temp1;
int temp2;
int temp3;

// create a variable frequency and amplitude sinewave.
// since we will be moving through the lookup table at
// a variable frequency, we wont always land directly
// on a single sample. so we will average between the
// two samples closest to us. this is called interpolation.
// step through the table at rate determined by mod1
// use upper byte of mod1 value to set the rate
// and have an offset of 1 so there is always an increment.
location += 1 + (mod1_value >> 8);
// if weve gone over the table boundary -> loop back
location &= 0x0003ffff; // this is a faster way doing the table
// wrap around, which is possible
// because our table is a multiple of 2.
// otherwise you would do something like:
// if (location >= 1024*256) {
// location -= 1024*256;
// }
temp0 = (location >> 8);
// get first sample and store it in temp1
temp1 = pgm_read_word_near(sinewave + temp0);
++temp0; // go to next sample
temp0 &= 0x03ff; // check if weve gone over the boundary.
// we can do this because its a multiple of 2,
// otherwise it would be:
// if (temp0 >= 1024) {
// temp0 = 0; // reset to 0
// }
// get second sample and put it in temp2
temp2 = pgm_read_word_near(sinewave + temp0);

// interpolate between samples
// multiply each sample by the fractional distance
// to the actual location value
frac = (location & 0x000000ff); // fetch the lower 8b
MultiSU16X8toH16(temp3, temp2, frac);
// scaled sample 2 is now in temp3, and since we are done with
// temp2, we can reuse it for the next result
MultiSU16X8toH16(temp2, temp1, 0xff - frac);
// temp2 now has the scaled sample 1
temp2 += temp3; // add samples together to get an average
// our sinewave is now in temp2

// set amplitude with mod0
// multiply our sinewave by the mod0 value
MultiSU16X16toH16(temp1, temp2, mod0_value);
// our sinewave is now in temp1

// create a tremolo effect by multiplying input signal by sinewave
// turn signed sinewave value into unsigned value
temp1 += 0x8000;
MultiSU16X16toH16(right_out, left_in, temp1);
// put amplitude modulated data at right output
// mix modulated and current data at left output
// divide each by 2 for proper scaling
left_out = (right_out >> 1) + (left_in >> 1);

// & is required before adc variables
AudioCodec_ADC(&mod0_value, &mod1_value);

// reti(); // dont forget to return from the interrupt
}
instantplaces
 
Posts: 6
Joined: Mon Aug 13, 2012 3:27 pm

Re: replace mod1_value with serial input from MAX MSP

Postby guest » Thu Aug 16, 2012 5:32 pm

change ADCS to 1
and get rid of the &mod1_value from the adc function call

its resetting itself everytime the adc is read
guest
Site Admin
 
Posts: 449
Joined: Thu May 20, 2010 11:58 pm


Return to Audio Codec Shield

Who is online

Users browsing this forum: No registered users and 1 guest


cron