Difference between revisions of "Therething"

From BuildBrighton
Jump to: navigation, search
(UPDATE: Generating Scales OR Control messages)
(UI code for the theremin)
Line 42: Line 42:
 
==== Generating Scales ====
 
==== Generating Scales ====
 
Code for generating MIDI note scales from a base note and the note intervals (in semitones).
 
Code for generating MIDI note scales from a base note and the note intervals (in semitones).
[[media:theremin_arduino_scale_test.pde]]
+
[[media:theremin_arduino_scale_test.pde|theremin_arduino_scale_test.pde]]
  
 
==== UPDATE: Generating Scales OR Control messages====
 
==== UPDATE: Generating Scales OR Control messages====
Line 48: Line 48:
 
I think all the options except the MIDI channel & inverting the ranges are in there.
 
I think all the options except the MIDI channel & inverting the ranges are in there.
 
[[Theremin/scales_and_controller_with_sensor_reading]]
 
[[Theremin/scales_and_controller_with_sensor_reading]]
 +
 +
==== User interface code ====
 +
Menu interface for the LCD display controlling global variables that could be picked up by the sensor code. [[Media:Theremin_UI.pde|Theremin_UI.pde]]
  
 
==== Getting note name for Display (snippets)====
 
==== Getting note name for Display (snippets)====

Revision as of 06:43, 18 October 2009

Theremin Project

We have been asked by Playgroup, local club promoters, to provide a 'sweetner' to perusade electronica djs [Evil Nine] to take part in an event they are promoting. This item is to be a Theremin. We therefore need to design and build a theremin to be presented to Evil Nine on 30th October 2009 at The Komedia (where we will also be hosting the pre-party from 6-10pm).

This is a lot of work to be done in a short amount of time, and the results must be professional. Volunteers wanted!

A few group members have already worked on MIDI projects and have discussed the idea of building a theremin-type machine with midi output. The analogue signal used to drive the oscillator/speaker on the original could be sampled to give a digital value within a specific range, which in turn can be used to generate a midi "note on/off" signal. The idea of using ultrasonic range finders in place of the theremin's antenna has also been thrown around. This would mean that the end result would be an instrument that plays like a theremin (non-contact) but is actually a completely different beast altogether.

How the BuildBrighton Theremin will work

Ultrasonic sensors are used to return a distance value, from the sensor to the player's hand. This value is converted by an Arduino or other microcontroller into a MIDI key value and is output at the correct baud rate (31,250 bps) onto a serial pin. Since MIDI needs a signal to turn off a key pitch as well as a signal to turn it on, it is recommended that when the note changes, two MIDI signals are sent - one to turn off the previous note and one to activate the required note. It may be possible to program some sort of delay/sustain effect in here, so that the off signal is delayed. This would mean that note changes are not too abrupt as there could be a slight overlap between notes.

Volume can be controlled using a similar approach, using an ultrasonic transducer (or transmit/receive pair) that is away from the note-generating sensor (to avoid cross-talk or interference). Alternatively, a potentiometer, slider or rotary encoder could be used to control volume.

Additionally, optional "effects pedals" could be introduced - time permitting - to alter the MIDI output: instead of a single note, a chord could be played (a major or minor triad) by pressing a foot-switch or rocker pedal. Stress sensors or rotary encoders could be used to implement pitch bending. These are outside the original remit, and unlikely to be ready in time for the impending Oct 30th deadline, but offer food for thought for future development.

User Interface Planning

UnTheremin UI.jpg

Menu Tree

  • Note Settings
    • Scale [None, Major, Minor, …]
    • Root [C, C#, …]
    • Octave [-2, -1, 0, 1, 2, 3]
    • Range [1 octave, 2 octaves, 3 octaves]
  • Controller Settings
    • Left
      • CC Number [0 - 127]
      • Invert Range [On, Off]
    • Right
      • CC Number [0 - 127]
      • Invert Range [On, Off]
  • MIDI Channel [1 - 16]

Prototype Code

Generating Scales

Code for generating MIDI note scales from a base note and the note intervals (in semitones). theremin_arduino_scale_test.pde

UPDATE: Generating Scales OR Control messages

Contains most of the MIDI code for the theremin. No setters for the options yet (sorry James) but I think all the options except the MIDI channel & inverting the ranges are in there. Theremin/scales_and_controller_with_sensor_reading

User interface code

Menu interface for the LCD display controlling global variables that could be picked up by the sensor code. Theremin_UI.pde

Getting note name for Display (snippets)

char* noteNames[] = {
  "C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};

char* getNoteName(int noteNumber){
  return noteNames[noteNumber % 12];
}

int getOctaveNumber(int noteNumber){
  return (noteNumber / 12) - 1;
}

Scales

'Ionian Mode','2212221'
'Dorian Mode','2122212'
'Phrygian Mode ','1222122'
'Lydian Mode','2221221'
'Mixolydian','2212212'
'Aeolian Mode','2122122'
'Locrian Mode','1221222'
'Major Scale','2212221'
'Harmonic Minor','2122131'
'Asc. Melodic Minor','2122221'
'Des. Melodic Minor','2122122'
'Natural Minor','2122122'
'Lydian Diminished','2131221'
'Lydian Augmented','2222121'
'Lydian b7','2221212'
'Locrian #2','2121222'
'Super Locrian','1212222'
'Whole Tone','2222222'
'Whole-Half Diminished','21212121'
'Half-Whole Diminished','12121212'
'Augmented','313131'
'Hindu','2212131'
'Major Pentatonic','22323'
'Minor Pentatonic','32232'
'Blues Scale','32232'
'Major Triad','2212221'
'(add 9)','2212221'
'SUS','2212221'
'(b5)','2211321'
'+ (augmented)','2213121'
'6','2212221'
'M7(b5),M9(#11)','2221221'
'M7,9,13','2221221'
'M7+,M9+','2213121'
'M13(#11)','2221221'
'Minor Triad','2122212'
'(add 9)','2122212'
'm6','2122212'
'o7 (diminished)','2121212'
'm7(b5)','1221222'
'm7,9,11,13','2122212'
'm(M7),m9(M7)','2122221'
'7,7sus,9,11,13','2212212'
'IV/V (Ex. F/G)','2221221'
'7(b5),9(#11),13(#11)','2221212'
'7(b9),11(b9),13(b9)','1312212'
'7(#9),13(#9)','3112212'
'7(b9#9)','1222212'
'7(b9b5),7(b9#11)','1311312'
'7+,9+','2213112'
'7+(#9)','1313112'
'7+(b9)','1313112'
'13(b9#11)','1321212'

Sending notes and midi CCs from one sensor

/*
	DistanceBySoftwareSerial.pde - URM 37 Control Library Version 2.0.0
 	Author: Miles Burton, [email protected]
 	Copyright (c) 2009 Miles Burton All Rights Reserved
 
 	This library is free software; you can redistribute it and/or
 	modify it under the terms of the GNU Lesser General Public
 	License as published by the Free Software Foundation; either
 	version 2.1 of the License, or (at your option) any later version.
 
 	This library 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
 	Lesser General Public License for more details.
 
 	You should have received a copy of the GNU Lesser General Public
 	License along with this library; if not, write to the Free Software
 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 */

#include "URMSerial.h"


// The measurement we're taking
#define DISTANCE 1
#define TEMPERATURE 2
#define ERROR 3
#define NOTREADY 4
#define TIMEOUT 5

#define SEND_CC true
#define SEND_NOTES false

URMSerial urm;

int prev;
int prevNote = 0;
int prevVel = 0;

void setup() {

  //  Set MIDI baud rate:
  Serial.begin(31250);

  urm.begin(4,3,9600);                 // RX Pin, TX Pin, Baud Rate
}

void loop()
{
  getMeasurement();  // Output measurement
}


int value; // This value will be populated
int getMeasurement()
{
  // Request a distance reading from the URM37
  switch(urm.requestMeasurementOrTimeout(DISTANCE, value)) // Find out the type of request
  {
  case DISTANCE: // Double check the reading we recieve is of DISTANCE type
    if(value < 80){
      if(SEND_CC){
        if(prev != value){
          prev = value;
          midiCC(12,value);
        }
      }

      if(SEND_NOTES){
        sendNote((value / 5) + 24);
      }
    }

    break;
  } 
  return 0;
}


// This function sends a Midi CC.
void midiCC(char c_num, char c_val){
  Serial.print(0xB0, BYTE);
  Serial.print(c_num, BYTE);
  Serial.print(c_val, BYTE);
}

void sendNote(char note){
  if(note != prevNote){
    //save the inputs so we can turn the 
    //note off when the next ones turned on
    prevNote = note;
    prevVel = 127;

    noteOff();
    noteOn(note, 127);
  }
}

//Sends a note on event over serial
void noteOn(char noteNo, char vel){
  Serial.print(0x90, BYTE);
  Serial.print(noteNo, BYTE);
  Serial.print(vel, BYTE);
}

//Sends a note on event over serial
void noteOff(){
  Serial.print(0x80, BYTE);
  Serial.print(prevNote, BYTE);
  Serial.print(prevVel, BYTE);
}

Videos

Links to source materials/ideas