Piezo sensor midi latency

Happy Holidays All
I'm working on my arduino midi controller and have progressed some thanks to your help. At the moment I am getting a lot of latency between the time I strike the piezo and when the note-on tone sounds and can be seen in the video below. Also the current working of the sketch if for a monophonic instrument. I would like to modify it to produce polyphonic sound i.e. more that one tone at a time independent of each other. I read somewhere of something called the modulo operation might help me achieve. And anyone help me with this and or perhaps another approach to polyphony.

I'm using a 4051 multiplexer. on the 4051 page on arduino.cc there in a liner approach to multiplexing which I'm using in my current sketch. however there is another way, the matrix which claims to be able to read multiple keys at at once. How would my current sketch have to be modifed to work with the the matrix version
here's my code https://sites.google.com/site/arduinosteeldrumcontroller/

here's a video clip голь на выдумки хитра (Digidrumduino) - YouTube

Arduino 4051 page Arduino Playground - 4051

My grown up Christmas wish https://plus.google.com/102734489235060266779/posts/PPXckAisqkm

Thank you in advance and All the best in 2012 and beyond!

Haven't reviewed your code, but from the video I could see that the latency between the piezo and the tone is highly variable. Sometimes it was really responsive, and at other times it really lagged. At one point in the video (0:14s - 0:18s) it outputted two tones, almost as if it was clearing out a buffer. This seems to be a problem with your interrupt handler.

Just to get some more clarification (and so future viewers can get up to speed without reading the code):

1- How are you currently handling the input from the piezo? I know you are using the multiplexer but try to walk me through the whole system, from input to tone output. Use pseudocode or simplified code to make it easier to digest.
2- Are you using interrupt request handlers?

This is just a guess, but I think this is a priority problem... the input from the piezo is not being treated with a high enough priority in the arduino. This could result in your variable lag; when the arduino has nothing to do it will service your request, but when it comes under load it will put the piezo request on hold. This also accounts for the double tone anomaly at (0:14s - 0:18s)... the arduino put the requests in a buffer, served some other request, came back and found that you had pressed a piezo twice and proceeded to play those two tones.

I'll have a look at your code when I have some free time, but in the meantime I suggest you look into your interrupt request handlers.

As for your other questions, the polyphonic problem is one of superimposing the digital equivalents of the analogue sound-wave together to get your desired result. As how you would go about doing that I don't really know at this stage... may look around my notes because I remember manipulating analogue waveforms with digital systems. As for the multiplexer matrix problem it would take some time to create an ideal solution; you'll probably have to sit down with a pen and paper and map out the matrix connections.

Let me know how you go with this...

interesting...
Mike noted

MIDI Footsteps. Introduction. This is a project I made as part of a large installation, however the rest of the installation is defined by software so I just want to present the hardware aspects here

http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html That may account for the lack of a said 'TIMEers'
I've done some reading and I think I get the gist it.
I am looking at YAMMI-Drum Arduino Forum as an example of setting the timers.
The sections of the YAAMi project that has to do specifically with timers, that I've been able to identify thus far are as follows

int PadCutOff[48] = {200,300,300,150,300,300,500,400,150,150,300,150,150,500,500,500,
300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,
300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300}; // Minimum Analog value to cause a drum hit, default=600

int MaxPlayTime[48] = {20,10,10,5,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10}; // Cycles before a 2nd hit is allowed, default=90

boolean activePad[48] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Array of flags of pad currently playing
int PinPlayTime[48] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Counter since pad started to play

// Making analog readings faster (for drumrolls) works with this code
// read http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11 for more info
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#if FASTADC
// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
#endif

YAMMIDRUM code here YAAMIDRUM download | SourceForge.net
I also realize that there are times that I do get double hits ( as is evident in the video ) which means that there is some degree of polyphonic action going on.

Still thinkering.
Thanks for the help.
Cheers

Calculating....
1)The speed at which read() takes place. i.e. the read/write speed of the eeprom.
2)PinPlayTime and MaxPlayTime // defines the max time any pin is allowed to play.

interesting...
Mike noted

MIDI Footsteps. Introduction. This is a project I made as part of a large installation, however the rest of the installation is defined by software so I just want to present the hardware aspects here

http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html That may account for the lack of a said 'TIMEers'
I've done some reading and I think I get the gist it.
I am looking at YAMMI-Drum Arduino Forum as an example of setting the timers.
The sections of the YAAMi project that has to do specifically with timers, that I've been able to identify thus far are as follows

int PadCutOff[48] = {200,300,300,150,300,300,500,400,150,150,300,150,150,500,500,500,
300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,
300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300}; // Minimum Analog value to cause a drum hit, default=600

int MaxPlayTime[48] = {20,10,10,5,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10}; // Cycles before a 2nd hit is allowed, default=90

boolean activePad[48] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Array of flags of pad currently playing
int PinPlayTime[48] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Counter since pad started to play

// Making analog readings faster (for drumrolls) works with this code
// read http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11 for more info
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#if FASTADC
// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
#endif

// CALIBRATE THE SENSOR
//for (i = 0; i < 400; i++) // make the calibration take about 10 seconds (6 sensors)
for (i = 0; i < 2400; i++) // make the calibration take about 10 seconds (1 sensor only)
{
qtra.calibrate(); // reads all sensors 10 times at 2.5 ms per six sensors (i.e. ~25 ms per call) => ~4.17 ms per call for ONE sensor!!! to get 0 seconds calibration use i=400*6
}

for (i = 0; i < NUM_SENSORS; i++){

int calibMinOn=qtra.calibratedMinimumOn*;*
_ int calibMaxOn=qtra.calibratedMaximumOn*;_
_
// save minimum value to eeprom*_
* // need to divide by 4 because analog inputs range from*
* // 0 to 1023 and each byte of the EEPROM can only hold a*
* // value*
> The ADC accuracy also depends on the ADC clock. The recommended maximum ADC clock frequency is limited by the internal DAC in the conversion circuitry. For optimum performance, the ADC clock should not exceed 200 kHz. However, frequencies up to 1 MHz do not reduce the ADC resolution significantly.
>
> Operating the ADC with frequencies greater than 1 MHz is not characterized.
>
>
> So looks like using a prescale of 16 as above would give an ADC clock of 1 MHz and a sample rate of ~77KHz without much loss of resolution. BTW, this is the code to set the prescale to 16:
>
>
>
> Code:
> // defines for setting and clearing register bits
> #ifndef cbi
> #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
> #endif
> #ifndef sbi
> #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
> #endif
>
> // set prescale to 16
> sbi(ADCSRA,ADPS2) ;
> cbi(ADCSRA,ADPS1) ;
> cbi(ADCSRA,ADPS0) ;

Hi,

to start off with, I know little about arduino programming AND little about your hardware setup.

But you SEEM to be just writing midi noteon events upon a piezo hit?
The midi event going to a windows based midi synth?

Do the sensors generate interrupts? Or do you poll them in a tight loop?

You shouldn't have to do any timing code (unless required by the sensors).
To do simultaneous notes, your sensors should be capable of generating input to
your arduino app simultaneously and then your arduino app turns the sensor
into a particular midi note for the drum sound.
The synthesizer on the pc should be capable of playing the notes at once.
(It's rare to find a synth that won't)

I think you'll need to do more explanation rather than providing links to code...

Somebody else's code is always harder to read than your own :slight_smile:

...Steve

1- How are you currently handling the input from the piezo? I know you are using the multiplexer but try to walk me through the whole system, from input to tone output. Use pseudocode or simplified code to make it easier to digest.
2- Are you using interrupt request handlers?

'Almightynassar'
the idea as currently implemented is: 1st send note off, then scans the inputs, look for change, the piezos when struck sends a signal, when that signal falls below a set thresshold it triggers a noteOn. And the loop starts again.
The noteOn message is made up of the sensorID and SensorValue. So thinking it terms of the knock example. the arduino sends to the synth which of x number of doors were knocked on, and how hard or soft that knock was/is. Each Door or sensor has it's own id. the first door or lowest not being LSM and the highest note ot last door, the MSB no two doors are the same.

The desires on/off action is that of a piano key.
2- no interrupt request handlers

Do the sensors generate interrupts? Or do you poll them in a tight loop?

thanks for your in put Steve the answer is the same as above ; no to interrupts

The midi event going to a windows based midi synth?

at the moment I using a hardware module, sometimes I may use a linux software synth or perhaps on a mac with logic.
Almightynassar's reply lead me to someone else's code and a forum post that talks about the seed of the read cycles . FASTADC

do a google search for arduino + polyphony and within the first 10 results you'll find

Sep 8, 2008 – I've yet to see a fully functional polyphonic synth powered solely by Arduino, but I think we're seeing the components of such a system coming ...
Evil Mad Science shared this on Google+ · Nov 13, 2011

On the issue os Time I have noticed other sketches that;

  1. sets PinPlayTime and MaxPlayTime // these values define the max time any pin is allowed to play.
  2. inserts a piec of code that set the seed of the arduino' internal timers
    code//

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;