Free Plans for an Arduino-Based DRSSTC MIDI Interrupter

Daniel Kramnik, Sat Jun 30 2012, 04:46AM

Hi all!

I've decided to post some plans for a dead-simple DRSSTC MIDI interrupter based on an Arduino and a handful of fairly basic off-the-shelf components. These plans should make it very easy for anyone to add audio modulation to their solid state coil.

MIDI parsing is done using the Arduino MIDI library, and notes are generated using 16-bit Timer1 in CTC mode - the output compare interrupt generates an output pulse with a duration retrieved from a lookup table to ensure that the output of the coil is roughly the same at every frequency. This lookup table is coil-specific and therefore experimentally determined.

I'm working on adding polyphony by using software counters with 8-bit Timer0 and Timer2 to extend them to 16 bits. Hopefully, this should be out in another few days or so (but no promises).

I've attached the Arduino sketch file, along with a tested Eagle CAD schematic and board layout for a standalone interrupter. The total parts cost is roughly $15, I will be releasing a Digikey bill of materials shortly.

Enjoy!

(If you have any comments about my code, or if you have ideas for features I should incorporate, feel free to suggest them here)

I am planning on selling a few of these boards, etched, drilled, assembled, programmed, and tested, on eBay (target price ~$40, shipped) to see if there is interest. Once these boards have been sold, I may send out a PCB fab order so that I can offer them as kits for even less money. The idea here is to make a basic, inexpensive, and easy to understand DRSSTC interrupter that anyone can add to their coil.

I've also included modified schematic and board files for Bwang's 1Tesla DRSSTC that are compatible with this interrupter. Note that the interrupter is an Eagle 5 file while the modified 1Tesla is an Eagle 6 file.

Here's a video of something very similar to this interrupter playing back music from a computer:


It also does polyphony, although I am unable to release the code for this at the moment:
Re: Free Plans for an Arduino-Based DRSSTC MIDI Interrupter
Daniel Kramnik, Sat Jun 30 2012, 04:55AM

I've tried again to upload the file - can an admin please delete the previous posts? It seems there's no way for me to try uploading a new file other than to post a reply, and there doesn't seem to be a way for me to delete my own replies if the upload fails...

In case you'd like to take a look at the code without unzipping the file, here it is:
/*
* Monophonic MIDI-Based DRSSTC Interrupter
* Daniel Kramnik, June 29, 2012
* Hardware:
*  - Optical transmitter connected to Port D.2 (Arduino Digital Pin 2) through 100 ohm resistor
*  - MIDI input connected to RXD (Arduino RX Pin) through 4N25 optocoupler circuit to isolate micro and prevent ground loops
*/

// MIDI class import - Note: this is not a standard Arduino library, it needs to be downloaded and added to your libraries folder
#include <MIDI.h>

// Function prototypes
void setupTimers     (void);
void setupInterrupts (void);
void HandleNoteOn    (byte, byte, byte);
int  findOnTime      (int);

// Global constants
#define PW_TABLE_MULTIPLIER  1.5

// Global primitives
volatile int on_time, current_pitch = 0;

void setup() {
  // Setup optical transmitter on Port D.2 (Digital Pin 2)
  DDRD  |=  (1 << 2);
  PORTD &= ~(1 << 2);    // Start the pin LOW (Note: you should *never* use digitalWrite to set this pin, as that function takes several microseconds
  
  setupTimers();
  setupInterrupts();
  
  // Initiate MIDI communications, listen to all channels
  MIDI.begin(MIDI_CHANNEL_OMNI);    
  
  // Setup MIDI callback functions (add more callback functions here to handle other MIDI events)
  MIDI.setHandleNoteOn(HandleNoteOn);    // Put only the name of the function
}

// Functions for setting up timer and interrupt reigsters
void setupTimers() {
  /*
    Timer1 is used to time the period of a note, with 0.5uS per tick
    When Timer1 reaches the compare value, an interrupt is triggered that generates the output pulse
  */
  
  // Set up 16-bit Timer1 (0.5uS per tick, hardware pins disconnected - interrupt starts disabled)
  TCCR1A = 0x00;                        // CTC mode, hardware pins disconnected
  TCCR1B = (1 << CS11) | (1 << WGM12);  // CTC mode, set prescaler to divide by 8 for 1 / 2MHz or 0.5uS per tick (clkio = 16MHz)
}

void setupInterrupts() {
  sei();    // Enable global interrupts to be safe, nothing else to do here
}

// Main program loop polls for MIDI events
void loop() {
  MIDI.read();
}

// MIDI callback functions
void HandleNoteOn(byte channel, byte pitch, byte velocity) {
  if (channel == 1) {
    if (velocity == 0) {  // Note off
      if (pitch == current_pitch) {
        TIMSK1 &= ~(1 << OCIE1A);    // Disable Timer1's overflow interrupt to halt the output
      }
    }
    else {  // Note on
        TIMSK1 &= ~(1 << OCIE1A);    // Disable Timer1's overflow interrupt to halt the output
        
        current_pitch = pitch;  // Store the pitch that will be played
        
        int frequency = (int) (220.0 * pow(pow(2.0, 1.0/12.0), pitch - 57) + 0.5);  // Decypher the pitch number
        int period = 1000000 / frequency;                                           // Perform period and calculation
        on_time = findOnTime(frequency);                                            // Get a value from the pulsewidth lookup table
        
        OCR1A   = 2 * period;     // Set the compare value
        TCNT1   = 0;              // Reset Timer1
        TIMSK1 |= (1 << OCIE1A);  // Enable the compare interrupt (start playing the note)
    }
  }
  else {
    // Ignore the command if it wasn't on channel 1 - this part may depend on the particular MIDI instrument you use, so modify the code here if you encounter a problem!
  }
}

// Pulsewidth lookup table
int findOnTime(int frequency_input) {
  int on_time = 17;
  if (frequency_input < 1000) {on_time = 17;}
  if (frequency_input < 900)  {on_time = 18;}  
  if (frequency_input < 800)  {on_time = 20;}
  if (frequency_input < 700)  {on_time = 20;}
  if (frequency_input < 600)  {on_time = 23;}
  if (frequency_input < 500)  {on_time = 27;}
  if (frequency_input < 400)  {on_time = 30;}  
  if (frequency_input < 300)  {on_time = 35;}
  if (frequency_input < 200)  {on_time = 40;}
  if (frequency_input < 100)  {on_time = 45;}       
  on_time *= PW_TABLE_MULTIPLIER;
  return on_time;
}

// Interrupt vectors
// Timer1 Compare Interrupt - signals when it's time to start a bang
ISR (TIMER1_COMPA_vect) {
  PORTD |= (1 << 2);           // Set the optical transmit pin high
  delayMicroseconds(on_time);  // Wait
  PORTD &= ~(1 << 2);          // Set the optical transmit pin low
}


]arduino_interrupter_and_1tesla.zip[/file]
Re: Free Plans for an Arduino-Based DRSSTC MIDI Interrupter
HB, Sat Jun 30 2012, 07:36PM

Nice work. I've also been working on a midi Arduino however i have very little programming knowledge. It can play poly using up to 3 seperate timers with outputs of each tied together but i ran into issues doing it that way. Sadly i went back to not combining the channels and can play alternating notes using more than 1 Tesla coil which will sound great once i build a few more coils. Anyhow i am looking forward to your Poly sketch to see how its all done up. Keep up the good work and its nice to see your willing to share.

edit: You can also use Link2 along with midi yoke to stream the midi to the Arduino with usb rather than use extra components if you wanna play midi directly from a pc. Its worked very well for me
Re: Free Plans for an Arduino-Based DRSSTC MIDI Interrupter
Killa-X, Sun Jul 01 2012, 05:45AM

Nice, I myself for awhile had one going, just tones though, no midi...using a LCD screen and encoders...will look into trying this for fun, hope to see more!

I'd be more interested in the polyphonic though, mono is boring and I already do that off a basic op-amp and FL-Studios :( hehe
Re: Free Plans for an Arduino-Based DRSSTC MIDI Interrupter
Paul_J., Sun Jul 01 2012, 03:41PM

Hello,

I would be interested in a kit.

Thanks,

Paul
Re: Free Plans for an Arduino-Based DRSSTC MIDI Interrupter
E.TexasTesla, Sun Aug 12 2012, 11:41PM

Thanks for the code, it works great.
One question, my coil produces very weak sparks while playing keyboard.
I would like to increase duration to get a few more cycles and more spark.

Im new to arduino and im not sure where to make a change.
on timedelay?
Re: Free Plans for an Arduino-Based DRSSTC MIDI Interrupter
Daniel Kramnik, Sun Aug 12 2012, 11:45PM

Nice job! (Got a video?)

You'll need to increase the values in the lookup table function - int findOnTime(int frequency_input)

Alternately, you could just increase the value of PW_TABLE_MULTIPLIER in the #defines from 1.5.