Sunday, November 7, 2010

Recording Light

There comes a time in the recording process that requires extreme concentration to catch the right take at the right time. However, there are times when someone outside the recording room might observe prolonged silence and think the "recording artist" might be asleep or writing blog posts when in reality they might be making a hit record ... eventually.

The answer is a recording light. In this case a MIDI controlled one. After the break I give a picture tour of the light, the control module and the source code.

The light itself is a 2 1/2" rigid conduit pull box I scored from the local home
 improvement warehouse for $5.00 US. Given they usually run close to $30.00 this was a deal.
Inside the pull box I mounted two low voltage night light sockets and 7 watt bulbs.  No LED's? Of course not. Incandescents are the way to go.
The lens is nothing more than a recycled lamp shade from a "designer" sconce type lamp. I applied vinyl lettering to this and mounted it with heavy screws consistent with the "Cold War era battleship" look of this light.
The control module is housed in a standard 2-gang metal handy box. This worked as I needed depth for the low voltage controller and the 120v switched plug.
From left to right we have the MIDI input (5-Pin DIN connector). Next is the status lamp. I need this mainly due to Logic 9's buggy implementation of their "Recording Light" control surface where the light could accidentally be left on if the record button is disengaged at certain points in the blink cycle. Next is a 1A fuse which protects the high volt relay from over-current. The USB input is to program the Arduino microcontroller board, normally it is not connected. The last input accepts a 9-12v adapter for low voltage power. Sure I could have built a power supply into the box but space is tight so I opted to just use an adapter. I could have also powered the board via MIDI given a 5 volt line on pin 3 though I decided what I have would do. I could also have used the USB for 5 volt power. Whew!
Here is the inside. You can see the Arduino controller board, the relay and MIDI optoisolator board, the 15A receptacle, and a bunch of wires.
Here is the MIDI optoisolator circuit and HV relay board. As the MIDI standard mandates electrical isolation between devices, optical isolation is the answer. The relay is transistor switched from the microcontroller.
Here is a better shot of the Arduino board. For hardcore microcontroller programmers, this is a bit sugar coated. For those of us who aren't quite electrical engineers not quite production software developers, it is a joy to work with and has many a powerful feature especially suited to this sort of thing. Oh yeah, it's inexpensive.
Here is the recording plugin in Logic.
With the lights off.
Here is the light up and running. When you arm a track in Logic, it blinks at the same rate as the button in each track. When you are actually recording it glows solid. What's even funnier is that when the light is blinking the relay is audibly switching and it sounds as if you are sitting in traffic waiting to hang a Louie.


It works as designed thus far, in fact too good. Before I added the lamp on the controller box had no way of knowing if the light was stuck on. During a late night recording session, my lovely wife saw the glowing light for quite some time and pining for sleep started to slip a note under the door telling me she was going to bed. Hearing her outside I opened the door and discovered the light on in err.

Indeed, she had just filed the first bug report.


For those interested below is the source code:
/*
 * MIDI controlled record light. For use with Logic 8/9 Record Light Control Surface plugin.
 * Bugs? YES Logic is entirely inconsistent in its implementation of this plugin. 
 * Toggling the light OFF at the wrong time in the cycle will leave the light ON 
 * Packing a Take Folder in Logic also triggers the light 
 * Opening Logic turns the light on, closing it turns the light off. Bug?
*/

/**
 * Project: Arduino Controlled Recording Light
 * File nane: recording_light.pde
 * Description: MIDI controlled record light. For use with 
 * Logic 8/9 Record Light Control Surface plugin.
 *   
 * @author Dave Sutton Copyright (C) 2010.
 * @version $Id: v0.1
 *   
 * @see The GNU Public License (GPL)
 */
/* 
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* Standard Defines **************************************************/
#define  ON   true
#define  OFF   false
#define  LIGHT   2
#define  MIDI_STAT_LOW  0 
#define  MIDI_STAT_HIGH  0x7F

/* MIDI Defines *****************************************************/
#define  DEVICE_MIDI_CHAN 15      /* Yeah it's hardcoded */
#define  NOTE_OFF            0x80
#define  NOTE_ON             0x90
#define  AFTERTOUCH          0xA0
#define  CONTROL_CHANGE      0xB0
#define  PROGRAM_CHANGE      0xC0
#define  CHANNEL_PRESSURE    0xD0
#define  PITCH_BEND          0xE0
#define  SYSTEM_PREFIX       0xF0    
#define  META                0xFF
#define  SEQUENCER_NUMBER    0x00    /* obsolete */
#define  TEXT                0x01
#define  COPYRIGHT           0x02
#define  TRACK_NAME          0x03
#define  INSTRUMENT          0x04
#define  LYRIC               0x05
#define  MARKER              0x06
#define  CUE                 0x07    
#define  END_OF_TRACK        0x2F
#define  TEMPO               0x51
#define  TIME_SIGNATURE      0x58
#define  PROPRIETARY         0x7F
#define  MIDI_CHANNEL        0x20    /* obsolete */ 
#define  MIDI_PORT           0x21    /* obsolete */ 
#define  SMPTE               0x54    
#define  KEY_SIG             0x59    
#define  SYSEX_START   0xF0
#define  SYSEX_END     0xF7
                                                     
static boolean light_status = OFF;
unsigned int data; 
unsigned long length;

unsigned long get_vlq() {
 byte data;
 unsigned long val;
 
 data = Serial.read();
 val = data & 0x7F;
 if (data & 0x80) {
  data = Serial.read();
  val = (val << 7) | (data & 0x7F);
  if (data & 0x80) {
   data = Serial.read();
   val = (val << 7) | (data & 0x7F);
   if (data & 0x80) {
    data = Serial.read();
    val = (val << 7) | data;
    if (data & 0x80) {
     return -1;
    }
   }
  }
 }
 return val;
}


void get_dump(unsigned long amount) {
 int i, dump; 
 for (i = 0; i < amount; ++i) {
  dump = Serial.read();
 }
}

void setup() {
Serial.begin(31250); /* Setup Baud for MIDI */
pinMode(LIGHT, OUTPUT); /* Setup pin  */   
}

void loop() {
 if (Serial.available() > 0) {
  if ((data = Serial.read()) == META) {
   switch (data= Serial.read()) {
    case END_OF_TRACK:
     get_dump(2);
     break;
    case MIDI_CHANNEL:        
    case MIDI_PORT:           
     get_dump(3);
     break;
    
    case SEQUENCER_NUMBER:    
    case TIME_SIGNATURE:      
    case KEY_SIG:             
     get_dump(4);
     break;
    
    case TEMPO:               
     get_dump(5);
     break;
    
    case SMPTE:               
     get_dump(7);
     break;
    
    case TEXT:                
    case COPYRIGHT:
    case TRACK_NAME:          
    case INSTRUMENT:          
    case LYRIC:               
    case MARKER:              
    case CUE:                 
    case PROPRIETARY:         
     get_dump(length = get_vlq());
       break;
    default:
    exit;
   }
   exit; 
  }

  if (data == SYSEX_START) {
   while ((data = Serial.read()) != SYSEX_END) {
    ;/*Just read and ignore */
   }
  }
  delay(10);
  
  switch (data & 0xF0) {
   case PROGRAM_CHANGE:      
   case CHANNEL_PRESSURE:    
    get_dump(1);
    break;
   case NOTE_OFF:            
   case AFTERTOUCH:          
   case CONTROL_CHANGE:      
   case PITCH_BEND:          
   case SYSTEM_PREFIX:       
    get_dump(2);
    break;

   case NOTE_ON:
    if ((data & 0x0F) == DEVICE_MIDI_CHAN) {
    delay(10);
     switch (data = Serial.read()) {
      case 0x18:
       switch (data = Serial.read())  { 
        case MIDI_STAT_LOW:
         digitalWrite(LIGHT, OFF);
         light_status == OFF;
         break;
        case MIDI_STAT_HIGH:
         digitalWrite(LIGHT, ON);
         light_status == ON;
         break;
        default:
         digitalWrite(LIGHT, OFF);
            light_status == OFF;
       } //end inner case
       break;
      case 0x19:
       if (light_status == OFF) {
        digitalWrite(LIGHT, ON);
        light_status == ON;
       } else {
        digitalWrite(LIGHT, OFF);
        light_status == OFF;
       }
       break;
      default:
          digitalWrite(LIGHT, OFF);
          light_status == OFF;
       break;
     } //end outer case
       } else {
     get_dump(2);
     exit; 

    }
    break;
      default:
   exit;
  }
 }
} // end void loop      


No comments:

Post a Comment