Skip to content

Instantly share code, notes, and snippets.

@zenwerk
Created November 3, 2017 16:07
Show Gist options
  • Save zenwerk/c0fd6a7ecbd5e227a2b280279b0d294b to your computer and use it in GitHub Desktop.
Save zenwerk/c0fd6a7ecbd5e227a2b280279b0d294b to your computer and use it in GitHub Desktop.
arduino_laser_harp.pde
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// MAKE MAGAZINE - LASER HARP FOR ARDUINO
// Stephen Hobley 2008
// www.stephenhobley.com
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Variables: ///////////////////////////////////////////////////////////////////////////////////////////
#define BEAMCOUNT 6 // レーザーの数
#define MIDICMD_NOTEON 0x90 // MIDIコマンド (Note On, Channel 0)
#define MIDICMD_CTRL 0xb0 // MIDI Controller message - channel 0
#define MIDICMD_PB 0xe0 // MIDI Pitchbend message - channel 0
#define MIDI_ROOT_NOTE 60 // テルミンのRoot note
#define MIDI_CONTROLLER 74 // Controller number
#define LOOPDELAY 10
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// データ構造
// These structures govern the behaviour of each of the 6 laser beams in harp mode
// access any of these arrays in the main polling loop <array>[i]
/////////////////////////////////////////////////////////////////////////////////////////////////////////
byte pinarray[BEAMCOUNT] = {2,3,4,5,6,7}; // Digital pins to read for laser beam breaks
byte analogarray[BEAMCOUNT] = {0,1,2,3,4,5}; // Analog pins to read for continuous data
byte notearray[BEAMCOUNT] = {64,63,62,60,59,58}; // MIDI note array - these are the notes that will play for each beam
// これがHIGHとなるpinは音を出す -> playarrayとは音を出す配列
// レーザーハープは光センサ(CDS)に光が当たっているときは, 音が出ない
// つまり,HIGH -> 無音, LOW -> 音を出す, ということに注意
byte playarray[BEAMCOUNT] = {HIGH,HIGH,HIGH,HIGH,HIGH,HIGH}; // The state of all beams to start with
// 距離センサの最大値 (浮動小数点数)
// TODO ここの値は環境によって微調整が必要
#define SENSORSCALE 1000.0 // Floating point maximum range for sensor - tweak this to find the best range
int iCounter = 0; // Counter used to reduce the sample rate
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This function takes the value from the GP2 sensor and calculates the MIDI controller value from it
// this is a bit slow as it uses floating point math
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// 距離センサの値からMidiコントローラの値を計算する関数
// 浮動小数点数演算のため若干動作が遅い
int ProcessAnalogValue(byte i)
{
// get a value for the GP sensor on pin i
// 指定されたpinの距離センサの値を読み込む
float _x = read_gp2d12_range_float(i);
// Truncate at 1000
// 1000より大きい値は切り捨て
if (_x > 1000.0)
_x = 1000.0;
// 0 - 127 is the full velocity range
// Midiベロシティの値は (1 - 127) の範囲
int _converted = (int)(_x/SENSORSCALE * 127.0);
// Now reverse the scale - louder closer to sensor
// scaleを反転する - センサに近いほど大きくする
//_converted = 127 - _converted;
// Midi信号送信
SendMIDI(MIDICMD_CTRL, MIDI_CONTROLLER, _converted );
return _converted;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Reads the GP2 sensor and returns the value in cms - floating point version - provided by Javier Valencia 2008
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// 距離センサの読み込み、cmsに変換して返す
float read_gp2d12_range_float(byte pin)
{
int tmp;
tmp = analogRead(pin); // pinからアナログ読み込み
if (tmp < 3) // 読み込まれる値は3未満を想定している
return -1.0; // invalid value
return (6787.0 /((float)tmp - 3.0)) - 4.0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Plays a MIDI note.
// Format of MIDI note on
// 1<xxx><yyyy> - xxx is 001 (Note On), yyyy is the channel number - in our case 0000 - which is channel 0
// 0<xxxxxxx> - note number 0-127
// 0<yyyyyyy> - note velocity 0-127 - instead of sending a note off, you can send 0 in this field to silence a note
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void SendMIDI(char cmd, char data1, char data2)
{
Serial.print(cmd);
Serial.print(data1);
Serial.print(data2);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// SETUP FUNCTION
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
// Set MIDI baud rate:
Serial.begin(31250);
//Serial.begin(9600);
pinMode(13, OUTPUT); // sets the digital pin as output
// 13pinから信号を出すので、midiケーブルとかは13pinにつなぐ
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// MAIN LOOP
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
// Loop through 6 inputs and find one that is different to how it was before
// if is is LOW, then note on, HIGH then note off..
// レーザーの数だけループ
for (int i= 0; i < BEAMCOUNT; i++)
{
// 1 Loop through 6 inputs and find one that is different to how it was before
// 読み込んだpinの状態が, 現在(一個前)の状態と違うか?
if ( digitalRead(pinarray[i]) != playarray[i] )
{
if (playarray[i] == HIGH)
{
// 音をだす (NOTE ON)
SendMIDI(MIDICMD_NOTEON, notearray[i], 127);
}
else
{
// 音を消す (NOTE OFF)
// Sound the MIDI note
SendMIDI(MIDICMD_NOTEON, notearray[i], 0); // Silence the note
}
// Finally flip the state of the playarray
// 最後に現在の状態を更新する
playarray[i] = !playarray[i];
}
// TODO ここの条件を変えると、回路側のCDSと抵抗を逆に接続可能
else if (playarray[i] == LOW) // 読み込んだ状態に変化がなく, かつ状態はLOWのまま
{
// Note: the update rate of the sensor is 25Hz - so we only need to read about once every 40ms - let's make it 30ms (3xLOOPDELAY) to be safe.
// If it is LOW then read analog pin and send out a pitchbend message
// センサの更新レートは25Hz, よって40ミリ秒毎に読み込めばよい.
// なので, 安全のため30ミリ秒 (3 x LOOPDELAY) のdelayをする.
// つまり,forloopを抜けると, 最後のdelayで必ずdelayが発生するので, iCounterが3になるまではLOWのPINが更新されることはない.
if (iCounter == 3) // delayカウンターが3つたまったら..
{
ProcessAnalogValue(analogarray[i]); // 値読み込み
iCounter = 0; // delay用のカウンタを0に戻す
}
iCounter++; // delay用のカウンタを+1
}
}
// Pause processing for 1/100 of a second - adjust this value to alter the response of the harp.
// 10ミリ秒処理止める.
// TODO この値は環境によって調整がいる
delay(LOOPDELAY);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment