Author Topic: Working on a polyphonic interrupter for atmega328p / Arduino UNO  (Read 174 times)

Offline Zipdox

  • High Voltage Enthusiast
  • *
  • Posts: 43
  • Karma: +0/-0
    • View Profile
Code: [Select]
#include <MIDI.h>

#define samplingRate 62500
#define maxPlayingNotes 2

MIDI_CREATE_DEFAULT_INSTANCE();

float midiNotes[] = {8.18, 8.66, 9.18, 9.72, 10.3, 10.91, 11.56, 12.25, 12.98, 13.75, 14.57, 15.43, 16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87, 32.7, 34.65, 36.71, 38.89, 41.2, 43.65, 46.25, 49, 51.91, 55, 58.27, 61.74, 65.41, 69.3, 73.42, 77.78, 82.41, 87.31, 92.5, 98, 103.83, 110, 116.54, 123.47, 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880, 932.33, 987.77, 1046.5, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760, 1864.66, 1975.53, 2093, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520, 3729.31, 3951.07, 4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040, 7458.62, 7902.13, 8372.02, 8869.84, 9397.27, 9956.06, 10548.08, 11175.3, 11839.82, 12543.85};

typedef struct {
    byte pitch;
    int onTime;
    int offTime;
    int hasBeenOn;
} Note;

Note getNoteTimes(byte pitch, float dutyCycle){
  float period = samplingRate/midiNotes[pitch];
  Note finalNote = {pitch, round(dutyCycle*period), round((1-dutyCycle)*period), 0};
  return finalNote;
}

volatile Note playingNotes[maxPlayingNotes];


void handleNoteOn(byte channel, byte pitch, byte velocity){
    for(int i = 0; i < maxPlayingNotes; i++){
        if(playingNotes[i].onTime == 0){ // 0 onTime means this note isn't in use
            playingNotes[i] = getNoteTimes(pitch, 0.1);
            break;
        }
    }
    digitalWrite(13, HIGH);
}

void handleNoteOff(byte channel, byte pitch, byte velocity){
    for(int i = 0; i < maxPlayingNotes; i++){
        if(playingNotes[i].pitch == pitch){
            playingNotes[i] = {0,0,0,0}; // 0 onTime means it doesn't play
        }
    }
    digitalWrite(13, LOW);
}

void handlePitchBend(byte channel, int bend){
  float bendfactor = (1+ (float) bend/8190);
  float dutyCycle = 0.1;
  for(int i = 0; i < maxPlayingNotes; i++){
      if(playingNotes[i].onTime == 0) continue;
      float period = samplingRate/(bendfactor * midiNotes[playingNotes[i].pitch]);
      playingNotes[i].onTime = round(dutyCycle*period);
      playingNotes[i].offTime = round((1-dutyCycle)*period);
  }
}




void setup(){
    for(int i = 0; i<(sizeof(playingNotes)/sizeof(playingNotes[0])); i++){
        playingNotes[i] = {0,0,0,0};
    }

    pinMode(9, OUTPUT);
    pinMode(13, OUTPUT);

  cli(); //stop interrupts
  // set Timer/Counter Control Register to 0
  TCCR2B = 0;
 
  OCR2A = 0; // = 16000000 / (freq*prescaler) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR2B |= (1 << CS20);
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
  sei(); //allow interrupts


  MIDI.setHandleNoteOn(handleNoteOn);
  MIDI.setHandleNoteOff(handleNoteOff);
  MIDI.setHandlePitchBend(handlePitchBend);
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop(){
    MIDI.read();
}

volatile bool shouldPlay;
ISR(TIMER2_COMPA_vect){

  shouldPlay = false;
 
  for(int i = 0; i < maxPlayingNotes; i++){
    if(playingNotes[i].onTime == 0) continue;
    playingNotes[i].hasBeenOn++;
    if(playingNotes[i].hasBeenOn > playingNotes[i].onTime){
      playingNotes[i].hasBeenOn = -playingNotes[i].offTime;
    }
    if(playingNotes[i].hasBeenOn >= 0){
        shouldPlay = true;
    }
  }

  if(shouldPlay){
    PORTB |= 1 << 1;
  }else{
    PORTB &= ~(1 << 1);
  }

}

Currently it can only play 2 notes at the same time or else it gets stuck unable to receiver MIDI commands to turn off. I'm nut sure why but I'm guessing because the lack of CPU time to process Serial data because of interrupts.

Offline Netzpfuscher

  • High Voltage Experimenter
  • **
  • Posts: 98
  • Karma: +5/-0
    • View Profile
Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #1 on: March 24, 2020, 05:35:24 PM »
Your code is full of float calculations. It's possible that you ran out of CPU time. Float calculations on a 8bit micro without floating point unit is extremely expensive.
If you make your calculations with integer arithmetic you save a lot CPU.

Offline Zipdox

  • High Voltage Enthusiast
  • *
  • Posts: 43
  • Karma: +0/-0
    • View Profile
Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #2 on: March 24, 2020, 06:10:09 PM »
Your code is full of float calculations. It's possible that you ran out of CPU time. Float calculations on a 8bit micro without floating point unit is extremely expensive.
If you make your calculations with integer arithmetic you save a lot CPU.
The float calculations are for higher accuracy so it's not as out tune. But I'll try and see if I can get better performance with int.

Offline Netzpfuscher

  • High Voltage Experimenter
  • **
  • Posts: 98
  • Karma: +5/-0
    • View Profile
Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #3 on: March 24, 2020, 06:47:08 PM »
You simply need fixed point  ;)

Take a look at the function after line 130:
https://github.com/Netzpfuscher/UD3/blob/master/common/ud3core/tasks/tsk_midi.c

Offline Zipdox

  • High Voltage Enthusiast
  • *
  • Posts: 43
  • Karma: +0/-0
    • View Profile
Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #4 on: March 24, 2020, 08:24:49 PM »
You simply need fixed point  ;)

Take a look at the function after line 130:
https://github.com/Netzpfuscher/UD3/blob/master/common/ud3core/tasks/tsk_midi.c
I'm not very experienced with C, what do you mean?

Offline Netzpfuscher

  • High Voltage Experimenter
  • **
  • Posts: 98
  • Karma: +5/-0
    • View Profile
Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #5 on: March 24, 2020, 09:09:40 PM »
To make it simple.
Let's use your MIDI-Table and pick a number: 18.35 you also can represent it with 1835 if you multiply it by 100 or 12543.85 which is the "same" as 1254385. Both numbers fit in a uint32. And calculations with int/uint are fast on a Atmel. Floats needs emulation in Software which is extremely slow. So you can multiply all of your numbers by 100 make your calculations and at the end you can divide by 100 to get the integer part and make modulo operation to get the fraction. You need to care yourself not to overflow the variables ;)
But this is not so fast than another way (which I use) the first example is decimal, a decimal division or multiplication on a system without a hardware multiplier/divider is slow. But a binary multiplication/division is very fast. It's a shift operation. Divide by 2 is a right shift multiply by 2 is a left shift which takes only one clock cycle ;)

Lets use the number 12543.85 you can use 16 bits to store the 12543 and 16 bits to store the .85.
fixed_point_number = (12543<<16) + ((85*65535)/100) = 822073752 = ‭‭0011000011111111 1101100110011000‬

The conversion only needs to be done once at the beginning and at the end of the calculation. Or use precalculated values for the frequency in this format ;) And is has another advantage. Lets say you need to put the result in a 16 bit PWM Block or a 16 Bit DAC. Then you need no back calculation to decimal. You take your 32bit fixed point value shift it right value = value >>16 and you have it for your PWM block  8) But that everything works right all numbers in a calculation needs to be in this format. For integers it is simple just shift left and right and you have it.

For all of this there are premade librarys just google a bit for fixed point math.
« Last Edit: March 24, 2020, 09:15:06 PM by Netzpfuscher »

Offline Zipdox

  • High Voltage Enthusiast
  • *
  • Posts: 43
  • Karma: +0/-0
    • View Profile
Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #6 on: March 24, 2020, 09:32:09 PM »
To make it simple.
Let's use your MIDI-Table and pick a number: 18.35 you also can represent it with 1835 if you multiply it by 100 or 12543.85 which is the "same" as 1254385. Both numbers fit in a uint32. And calculations with int/uint are fast on a Atmel. Floats needs emulation in Software which is extremely slow. So you can multiply all of your numbers by 100 make your calculations and at the end you can divide by 100 to get the integer part and make modulo operation to get the fraction. You need to care yourself not to overflow the variables ;)
But this is not so fast than another way (which I use) the first example is decimal, a decimal division or multiplication on a system without a hardware multiplier/divider is slow. But a binary multiplication/division is very fast. It's a shift operation. Divide by 2 is a right shift multiply by 2 is a left shift which takes only one clock cycle ;)

Lets use the number 12543.85 you can use 16 bits to store the 12543 and 16 bits to store the .85.
fixed_point_number = (12543<<16) + ((85*65535)/100) = 822073752 = ‭‭0011000011111111 1101100110011000‬

The conversion only needs to be done once at the beginning and at the end of the calculation. Or use precalculated values for the frequency in this format ;) And is has another advantage. Lets say you need to put the result in a 16 bit PWM Block or a 16 Bit DAC. Then you need no back calculation to decimal. You take your 32bit fixed point value shift it right value = value >>16 and you have it for your PWM block  8) But that everything works right all numbers in a calculation needs to be in this format. For integers it is simple just shift left and right and you have it.

For all of this there are premade librarys just google a bit for fixed point math.
I will try to convert it to fixed point.

High Voltage Forum

Re: Working on a polyphonic interrupter for atmega328p / Arduino UNO
« Reply #6 on: March 24, 2020, 09:32:09 PM »

 


* Recent Topics and Posts

post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
davekni
Today at 02:05:07 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
SteveN87
Today at 01:20:11 AM
post Re: Corona lockdown thread, tell about your situation
[General Chat]
klugesmith
April 09, 2020, 11:42:29 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
MRMILSTAR
April 09, 2020, 08:27:37 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
ElectroXa
April 09, 2020, 07:37:01 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
davekni
April 09, 2020, 06:56:43 PM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
petespaco
April 09, 2020, 05:38:35 PM
post Re: Interuppter code help for sstc (LONEOCEANS SSTC2 )
[Solid State Tesla Coils (SSTC)]
prabhatkumar
April 09, 2020, 04:11:09 PM
post ST.COM reference design: 15 kW, 3-phase Vienna rectifier PFC
[Transformer (Ferrite Core)]
Mads Barnkob
April 09, 2020, 01:18:41 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
Jun
April 09, 2020, 12:29:40 PM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
SteveN87
April 09, 2020, 12:19:57 PM
post Re: Has anybody got this board?
[Solid State Tesla Coils (SSTC)]
oneKone
April 09, 2020, 07:33:27 AM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
davekni
April 09, 2020, 06:38:45 AM
post Re: Power MOSFETs with fast recovery body diodes
[Electronic Circuits]
John123
April 09, 2020, 06:33:52 AM
post Re: Power MOSFETs with fast recovery body diodes
[Electronic Circuits]
davekni
April 09, 2020, 05:47:51 AM
post Re: Power MOSFETs with fast recovery body diodes
[Electronic Circuits]
John123
April 09, 2020, 05:32:41 AM
post Re: Power MOSFETs with fast recovery body diodes
[Electronic Circuits]
T3sl4co1l
April 09, 2020, 05:10:31 AM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
ZakW
April 09, 2020, 04:17:27 AM
post Re: Power MOSFETs with fast recovery body diodes
[Electronic Circuits]
John123
April 08, 2020, 11:40:04 PM
post Has anybody got this board?
[Solid State Tesla Coils (SSTC)]
TMS
April 08, 2020, 10:34:42 PM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
John123
April 08, 2020, 07:53:19 PM
post Re: GDT keeps on killing IGBTs
[Dual Resonant Solid State Tesla coils (DRSSTC)]
davekni
April 08, 2020, 04:15:12 AM
post Re: GDT keeps on killing IGBTs
[Dual Resonant Solid State Tesla coils (DRSSTC)]
ritaismyconscience
April 08, 2020, 01:05:28 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
SteveN87
April 08, 2020, 12:53:15 AM
post Re: GDT keeps on killing IGBTs
[Dual Resonant Solid State Tesla coils (DRSSTC)]
davekni
April 07, 2020, 10:54:57 PM
post Re: GDT keeps on killing IGBTs
[Dual Resonant Solid State Tesla coils (DRSSTC)]
ritaismyconscience
April 07, 2020, 10:24:16 PM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
ZakW
April 07, 2020, 09:22:16 PM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
johnf
April 07, 2020, 09:04:34 PM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
ZakW
April 07, 2020, 08:48:01 PM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
Weston
April 07, 2020, 08:15:43 PM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
John123
April 07, 2020, 06:23:47 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
John123
April 07, 2020, 05:59:09 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
alan sailer
April 07, 2020, 04:30:26 PM
post Re: Powerful easy to build MIDI Interrupter
[Computers, Microcontrollers, Programmable Logic, Interfaces and Displays]
Max
April 07, 2020, 01:10:30 PM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
SteveN87
April 07, 2020, 12:44:56 PM
post Re: Where is plasma globe arc arcing to?
[Beginners]
John123
April 07, 2020, 07:05:30 AM
post Re: Where is plasma globe arc arcing to?
[Beginners]
Jun
April 07, 2020, 06:40:02 AM
post Re: Class E SSTC Topology
[Solid State Tesla Coils (SSTC)]
ZakW
April 07, 2020, 05:07:31 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
John123
April 07, 2020, 03:38:12 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
SteveN87
April 07, 2020, 03:21:55 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
John123
April 07, 2020, 02:59:28 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
davekni
April 07, 2020, 02:52:19 AM
post Re: Small DIY plasma globe using ZVS oscillator
[Transformer (Ferrite Core)]
John123
April 07, 2020, 02:29:21 AM
post Re: Where is plasma globe arc arcing to?
[Beginners]
John123
April 07, 2020, 02:21:55 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
John123
April 07, 2020, 02:00:26 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
SteveN87
April 07, 2020, 01:25:47 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
John123
April 07, 2020, 12:38:59 AM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
petespaco
April 07, 2020, 12:13:11 AM
post Re: Corona lockdown thread, tell about your situation
[General Chat]
John123
April 06, 2020, 10:07:59 PM
post Re: TVS diode selection for 400v transistor
[Electronic Circuits]
davekni
April 06, 2020, 10:07:11 PM

Sitemap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
SimplePortal 2.3.6 © 2008-2014, SimplePortal