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

Offline Zipdox

  • High Voltage Enthusiast
  • *
  • Posts: 46
  • 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 Technician
  • ***
  • Posts: 105
  • 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: 46
  • 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 Technician
  • ***
  • Posts: 105
  • 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: 46
  • 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 Technician
  • ***
  • Posts: 105
  • 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: 46
  • 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: Easy to build Polyphonic MIDI Interrupter
[Computers, Microcontrollers, Programmable Logic, Interfaces and Displays]
AstRii
Today at 01:04:06 AM
post Re: Moving to a new lab!
[Laboratories, Equipment and Tools]
profdc9
Today at 12:55:12 AM
post Re: Air Gap: why and how much?
[Transformer (Ferrite Core)]
profdc9
August 13, 2020, 10:59:27 PM
post Re: How about some Tesla Coil memes
[General Chat]
TMaxElectronics
August 13, 2020, 09:55:27 PM
post Re: Air Gap: why and how much?
[Transformer (Ferrite Core)]
johnf
August 13, 2020, 09:45:58 PM
post Re: Air Gap: why and how much?
[Transformer (Ferrite Core)]
klugesmith
August 13, 2020, 08:26:56 PM
post Re: Easy to build Polyphonic MIDI Interrupter
[Computers, Microcontrollers, Programmable Logic, Interfaces and Displays]
Max
August 13, 2020, 07:02:24 PM
post Air Gap: why and how much?
[Transformer (Ferrite Core)]
HighVoltageRulezz
August 13, 2020, 06:23:24 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
HighVoltageRulezz
August 13, 2020, 06:15:16 PM
post Re: How about some Tesla Coil memes
[General Chat]
AstRii
August 13, 2020, 05:26:47 PM
post Re: First DRSSTC, No Sparks on Breakout
[Dual Resonant Solid State Tesla coils (DRSSTC)]
TMaxElectronics
August 13, 2020, 05:25:43 PM
post Re: How about some Tesla Coil memes
[General Chat]
TMaxElectronics
August 13, 2020, 05:23:40 PM
post Re: First DRSSTC, No Sparks on Breakout
[Dual Resonant Solid State Tesla coils (DRSSTC)]
AstRii
August 13, 2020, 05:23:37 PM
post Re: Bipolar high voltage multiplier project - more than 70cm hot arc discharge
[Voltage Multipliers]
kilovolt
August 13, 2020, 01:44:24 PM
post How about some Tesla Coil memes
[General Chat]
AstRii
August 13, 2020, 01:09:16 PM
post First DRSSTC, No Sparks on Breakout
[Dual Resonant Solid State Tesla coils (DRSSTC)]
Yak
August 13, 2020, 12:41:06 PM
post Re: X-ray image intensifier
[X-ray]
AlexanderHun
August 13, 2020, 11:01:46 AM
post Re: Easy to build Polyphonic MIDI Interrupter
[Computers, Microcontrollers, Programmable Logic, Interfaces and Displays]
AstRii
August 13, 2020, 02:09:13 AM
post Re: Charging a LiPo Battery with an LED driver
[Electronic Circuits]
davekni
August 12, 2020, 11:08:35 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
davekni
August 12, 2020, 10:49:52 PM
post Re: Moving to a new lab!
[Laboratories, Equipment and Tools]
Mads Barnkob
August 12, 2020, 10:30:54 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
Teravolt
August 12, 2020, 09:00:50 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
SteveN87
August 12, 2020, 07:16:43 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
Teravolt
August 12, 2020, 02:54:33 PM
post Re: Charging a LiPo Battery with an LED driver
[Electronic Circuits]
TMaxElectronics
August 12, 2020, 12:42:50 PM
post Re: Charging a LiPo Battery with an LED driver
[Electronic Circuits]
Twospoons
August 12, 2020, 12:23:58 PM
post Re: Single sided use of Xray XFMR
[Transformer (Ferrite Core)]
HighVoltageRulezz
August 12, 2020, 11:15:07 AM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
davekni
August 12, 2020, 04:41:24 AM
post Re: Charging a LiPo Battery with an LED driver
[Electronic Circuits]
davekni
August 12, 2020, 04:06:09 AM
post Re: Charging a LiPo Battery with an LED driver
[Electronic Circuits]
TMaxElectronics
August 12, 2020, 01:58:47 AM
post Re: Charging a LiPo Battery with an LED driver
[Electronic Circuits]
Twospoons
August 12, 2020, 12:56:02 AM
post Charging a LiPo Battery with an LED driver
[Electronic Circuits]
TMaxElectronics
August 11, 2020, 11:24:18 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
Teravolt
August 11, 2020, 06:34:05 PM
post Re: Fun with wireless power
[Solid State Tesla Coils (SSTC)]
Lightning On Demand
August 11, 2020, 04:19:01 AM
post Re: Fun with wireless power
[Solid State Tesla Coils (SSTC)]
Lightning On Demand
August 11, 2020, 04:17:27 AM
post Re: Fun with wireless power
[Solid State Tesla Coils (SSTC)]
Lightning On Demand
August 11, 2020, 04:10:34 AM
post Re: Single sided use of Xray XFMR
[Transformer (Ferrite Core)]
klugesmith
August 11, 2020, 03:33:02 AM
post Single sided use of Xray XFMR
[Transformer (Ferrite Core)]
HighVoltageRulezz
August 10, 2020, 12:23:05 PM
post Re: XRay Tank- any ideas about what is inside
[Transformer (Ferrite Core)]
HighVoltageRulezz
August 10, 2020, 12:18:04 PM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
johnf
August 10, 2020, 10:24:54 AM
post Re: making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
davekni
August 10, 2020, 06:20:04 AM
post Re: Welcome new members, come say hello and tell a little about yourself :)
[General Chat]
RoadReaper
August 10, 2020, 05:40:19 AM
post Re: Easy to build Polyphonic MIDI Interrupter
[Computers, Microcontrollers, Programmable Logic, Interfaces and Displays]
Max
August 10, 2020, 02:07:26 AM
post making HV bobbins for ferrite transformers
[Transformer (Ferrite Core)]
Teravolt
August 10, 2020, 01:27:22 AM
post A Tesla coil and an antenna
[General Chat]
TheFreq
August 09, 2020, 09:02:32 PM
post Re: Fun with wireless power
[Solid State Tesla Coils (SSTC)]
Steve Ward
August 08, 2020, 10:22:04 PM
post Re: Fun with wireless power
[Solid State Tesla Coils (SSTC)]
T3sl4co1l
August 08, 2020, 03:36:40 PM
post Re: Fun with wireless power
[Solid State Tesla Coils (SSTC)]
acmq
August 08, 2020, 02:07:52 AM
post Re: LSI Nitrogen Laser tear-down and Homemade TEA Nitrogen and Dye Lasers
[Light, Lasers and Optics]
LesWright
August 06, 2020, 10:20:12 PM
post Re: LSI Nitrogen Laser tear-down and Homemade TEA Nitrogen and Dye Lasers
[Light, Lasers and Optics]
Weston
August 06, 2020, 08:45:59 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