Go Down

Topic: Reading MIDI, converting to polyphonic square wave with Tone library (Read 8007 times) previous topic - next topic

DerStrom8


No that is annoying and it happens to all of us. The real solution is to routinely copy your reply before you hit post.


Oh well, it was worth a try....  XD

Quote
Quote
You can have PWM while also changing the frequency...................

No you can't.
What you describe is not PWM. It is PPM, that is pulse position modulation.


How is setting the frequency yourself and then adjusting the pulse width different from having a previously set frequency and then adjusting the pulse width? It's still PWM, regardless of the frequency it's set at. Therefore, setting the signal to a specific frequency (note), and then adjusting the pulse width is still PWM (not the frequency adjustment part, but the pulse width adjustment part).

Anyway, I think I have the indexing down. I have the notes stored in an array. I'm thinking I would like a function that is triggered almost continuously (not literally, but apparently) to check the values in the array and play the notes, but make sure that it has a maximum on-time of 1mS. I expect I would want to use the timer1 interrupt to constantly check on the array, but when it comes to playing the notes, I'm not sure how I'd do that. Different timer, I guess?

Thanks for the help. I think we're just getting caught up on the terminology. I'm not saying adjusting frequency is part of PWM. I'm saying that you can set the frequency yourself, and then apply PWM.

Regards,
Matt

Grumpy_Mike

Quote
but also be able to adjust the duty cycle (apply PWM) in order to prevent the on-time from exceeding 1mS.

Why is this?
Altering the pulse width in a PPM system, ( you might like to think it is PWM but the rest of the world will disagree and it is important to use words in the same way as every one else ) will affect the timbre of the note, why do you want to do this?
It seems like you are over complicating matters with this.

DerStrom8

#17
Jul 29, 2014, 12:10 am Last Edit: Jul 29, 2014, 12:17 am by DerStrom8 Reason: 1

Quote
but also be able to adjust the duty cycle (apply PWM) in order to prevent the on-time from exceeding 1mS.

Why is this?
Altering the pulse width in a PPM system, ( you might like to think it is PWM but the rest of the world will disagree and it is important to use words in the same way as every one else ) will affect the timbre of the note, why do you want to do this?
It seems like you are over complicating matters with this.


PPM is different, and is not what I am referring to. I know the difference between PPM and PWM, and I am still referring to PWM.

If I am not mistaken, the standard frequency used for most PWM pins on the Uno is 490 Hz. I intend to change the frequency before applying PWM. For example, for an A4 note, I would set the frequency to 440 Hz. Then I can use PWM to reduce or increase the duty cycle (at that set 440 Hz). It is still PWM, it just happens to be based on a different frequency. I'm not sure if I can make this any clearer. I am not new to waveforms or modulation, and I do know what I am talking about. Being able to express my thoughts, however, is not my strongpoint...  :~  XD

I thought I had mentioned this before, but I need to prevent the on-time from exceeding 1mS because this project will eventually be used to control a Tesla coil. If the on-time is too long, it will cause severe overheating in the drive transistors, which could damage them. Therefore, regardless of the note, I need the duty cycle to be set so that any given pulse is not longer than 1mS.

Sorry once again for the confusion. I hope you can understand what I'm trying to say.
Regards,
Matt

EDIT: It occurred to me, I should probably refer to the duty cycle rather than PWM. I want to set the duty cycle in such a way as to prevent the on-time from exceeding 1mS regarless of the frequency. I think that may be where we're getting confused.

Grumpy_Mike

Quote
I thought I had mentioned this before, but I need to prevent the on-time from exceeding 1mS because this project will eventually be used to control a Tesla coil

The only mention of Tesla in the thread was a comment it the code saying you probably didn't need this for a Tesla coil, so you didn't exactly go out of your way to mention it.

The problem with using the timers in the PWM mode for doing PPM is that the resolution of them will not allow you to derive all the musical notes you want.

What is wrong with the phase accumulation method of generating notes?

DerStrom8


The only mention of Tesla in the thread was a comment it the code saying you probably didn't need this for a Tesla coil, so you didn't exactly go out of your way to mention it.

The problem with using the timers in the PWM mode for doing PPM is that the resolution of them will not allow you to derive all the musical notes you want.

What is wrong with the phase accumulation method of generating notes?


In that case, my apologies. I have three threads going on on three different forums involving different parts of this project, so I must have mentioned it on one of them. Sorry about that--I am not keeping up very well  :P

I'm not familiar with phase accumulation, though it has been brought up a couple of times. I'll have to look it up. Do you have any recommended links? If not, that's fine--I'll do some searching to see what I can find.

Thanks again!
Matt

DerStrom8

HI guys,

I've made a few changes and thought I'd post here.

I have decided to go the route of Bresenham accumulators and use the timer directly. Here is what I have to go on:

Code: [Select]
#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>
#include <TimerOne.h>
#include <avr/pgmspace.h>

#define TIMER_OVF_PERIOD 51  //period in uS before Timer1 triggers the interrupt
#define MAX_ON_TIME 1       //10 to give ~510uS per pulse, 1 for 51uS
#define MODE_NUM 3           //number of modes

/* Output Tone Pins */
int tone1pin = 3;
int tone2pin = 5;
int tone3pin = 6;

volatile int mode;

/* Note Status (On/Off) */
boolean note1on = false;
boolean note2on = false;
boolean note3on = false;

/* 32-bit Bresenham Accumulators */
unsigned long bres1 = 0;
unsigned long bres2 = 0;
unsigned long bres3 = 0;

/* 32-bit Note Frequencies */
unsigned long note1freq;
unsigned long note2freq;
unsigned long note3freq;

/* Note On-Time Counters */
int note1_on_time = MAX_ON_TIME;
int note2_on_time = MAX_ON_TIME;
int note3_on_time = MAX_ON_TIME;

/* MIDI Data Information */
volatile double note;
volatile int type, velocity, channel, d1, d2;

void setup() {
  pinMode(tone1pin, OUTPUT);          // tone output pins
  pinMode(tone2pin, OUTPUT);
  pinMode(tone3pin, OUTPUT);

  MIDI.begin(MIDI_CHANNEL_OMNI);
 
  Timer1.initialize(TIMER_OVF_PERIOD);    //trigger the interrupt at specified number of uS
  Timer1.attachInterrupt(noteISR);        //attach interrupt service routine to Timer1
  Serial.begin(57600);
}

void loop() {
   
    if (MIDI.read()) {
      byte type = MIDI.getType();
      switch (type) {
        case NoteOn:
          note = 440.0 * pow(2.0, ((double)(MIDI.getData1()-69.0)/12.0));  //get note frequency
          velocity = MIDI.getData2();
          channel = MIDI.getChannel();
          if (velocity > 0) {
            if (!note1on) {
              note1freq = note;
              note1on = true;
            } else if (!note2on) {
              note2freq = note;
              note2on = true;
            } else if (!note3on) {
              note3freq = note;
              note3on = true;
            }
          } else {
            if (note1freq == note) note1on = false;
            else if (note2freq == note) note2on = false;
            else if (note3freq == note) note3on = false;
          }
          break;
        case NoteOff:
          note = 440.0 * pow(2.0, ((double)(MIDI.getData1()-69.0)/12.0));  //get note frequency
          //determine which pin is playing the note and turn it off
          if (note1freq == note) note1on = false;
          else if (note2freq == note) note2on = false;
          else if (note3freq == note) note3on = false;
          break;
        default:
          break;
      }
    }
  }
}

/*****************************
* Interrupt Service Routine *
*****************************/

void noteISR() {
 
  /* Note 1 */
  if (note1on) {
    bres1 += note1freq * 64;
    if (bres1 >= (19531.25 * 64)) {
      bres1 -= (19531.25 * 64);
      note1_on_time = MAX_ON_TIME;
    }
  }
  if (note1_on_time > 0) {
    note1_on_time--;
    //Serial.println(note_on_time);
    digitalWrite(tone1pin, HIGH);
  } else {
    digitalWrite(tone1pin, LOW);
  }
 
  /* Note 2 */
  if (note2on) {
    bres2 += note2freq * 64;
    if (bres2 >= (19531.25 * 64)) {
      bres2 -= (19531.25 * 64);
      note2_on_time = MAX_ON_TIME;
    }
  }
  if (note2_on_time > 0) {
    note2_on_time--;
    //Serial.println(note_on_time);
    digitalWrite(tone2pin, HIGH);
  } else {
    digitalWrite(tone2pin, LOW);
  }
 
  /* Note 3 */
  if (note3on) {
    bres3 += note3freq * 64;
    if (bres3 >= (19531.25 * 64)) {
      bres3 -= (19531.25 * 64);
      note3_on_time = MAX_ON_TIME;
    }
  }
  if (note3_on_time > 0) {
    note3_on_time--;
    //Serial.println(note_on_time);
    digitalWrite(tone3pin, HIGH);
  } else {
    digitalWrite(tone3pin, LOW);
  }
}


Unfortunately, I constantly get stuck notes and can't seem to figure out why. I was hoping someone could look over the code for me.

The specifications have changed a bit. I need each note frequency to have a duty cycle with an on-time that stays at around 50uS. That's what TIMER_OVF_PERIOD and MAX_ON_TIME do. I am using the MIDI library found here: https://www.pjrc.com/teensy/td_libs_MIDI.html

I'm afraid there's not much more info I can give you right now. I'm stumped.

Thanks for any insight you can offer.
Regards,
Matt

Go Up