--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+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 or version 3.
+
+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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+// This is the laser harp projection, which is just a simple OpenLase app */
+
+#include "libol.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+int offs[12] = {
+ 0,1,0,1,0,0,1,0,1,0,1,0
+};
+float pos[12] = {
+ 0,0.5,1,1.5,2,3,3.5,4,4.5,5,5.5,6
+};
+
+int main (int argc, char *argv[])
+{
+ OLRenderParams params;
+
+ memset(¶ms, 0, sizeof params);
+ params.rate = 48000;
+ params.on_speed = 2.0/100.0;
+ params.off_speed = 2.0/30.0;
+ params.start_wait = 4;
+ params.start_dwell = 3;
+ params.curve_dwell = 0;
+ params.corner_dwell = 4;
+ params.curve_angle = cosf(30.0*(M_PI/180.0)); // 30 deg
+ params.end_dwell = 2;
+ params.end_wait = 5;
+ params.snap = 1/100000.0;
+ params.render_flags = RENDER_GRAYSCALE;
+
+ if(olInit(3, 30000) < 0)
+ return 1;
+
+ olSetRenderParams(¶ms);
+
+ float time = 0;
+ float ftime;
+ int i;
+
+ int frames = 0;
+
+ int points = 25;
+
+ while(1) {
+ olLoadIdentity();
+
+ int total_y = (points / 12.0 * 7.0 + 1);
+
+ for (i=0; i<points; i++) {
+ int octave = i/12;
+ float y = (octave * 7 + pos[i%12]) * 2.0 / (total_y) - 1.0;
+ float x = offs[i%12] * 0.1;
+ olDot(x, y, 30, C_WHITE);
+ }
+
+ ftime = olRenderFrame(60);
+ frames++;
+ time += ftime;
+ printf("Frame time: %f, FPS:%f\n", ftime, frames/time);
+ }
+
+ olShutdown();
+ exit (0);
+}
+
--- /dev/null
+# OpenLase - a realtime laser graphics toolkit
+#
+# Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+#
+# 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 or version 3.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This is the laser harp sensing portion, which has nothing to do with OpenLase.
+# You need OpenCV (2.2.0) and PyALSA installed
+# Pass the destination ALSA MIDI client:port pair as an argument.
+
+# You may need to edit some constants here
+
+THRESHOLD=200
+WIDTH=320
+HEIGHT=240
+
+NOTE_OFFSET=47
+
+VELOCITY=90
+
+import sys, math
+import cv
+
+from pyalsa import alsaseq
+
+seq = alsaseq.Sequencer(name="default", clientname=sys.argv[0], streams = alsaseq.SEQ_OPEN_DUPLEX, mode = alsaseq.SEQ_NONBLOCK)
+port = seq.create_simple_port(
+ name='out',
+ type = alsaseq.SEQ_PORT_TYPE_MIDI_GENERIC | alsaseq.SEQ_PORT_TYPE_APPLICATION,
+ caps = alsaseq.SEQ_PORT_CAP_READ | alsaseq.SEQ_PORT_CAP_SUBS_READ)
+
+def note(n, state=False):
+ if state:
+ etype = alsaseq.SEQ_EVENT_NOTEON
+ else:
+ etype = alsaseq.SEQ_EVENT_NOTEOFF
+ event = alsaseq.SeqEvent(type=etype)
+ event.set_data({'note.channel': 0, 'note.note': n, 'note.velocity': 90})
+ seq.output_event(event)
+ seq.drain_output()
+
+if len(sys.argv) > 1:
+ toport = seq.parse_address(sys.argv[1])
+ seq.connect_ports((seq.client_id, port), toport)
+
+camera = cv.CreateCameraCapture(0)
+cv.SetCaptureProperty(camera, cv.CV_CAP_PROP_FRAME_WIDTH, WIDTH)
+cv.SetCaptureProperty(camera, cv.CV_CAP_PROP_FRAME_HEIGHT, HEIGHT)
+cv.SetCaptureProperty(camera, cv.CV_CAP_PROP_BRIGHTNESS, 0)
+
+image = cv.QueryFrame(camera)
+grey = cv.CreateImage(cv.GetSize(image), cv.IPL_DEPTH_8U, 1)
+grey2 = cv.CreateImage(cv.GetSize(image), cv.IPL_DEPTH_8U, 1)
+
+def getpoints(image):
+ points = []
+ cv.CvtColor(image, grey, cv.CV_RGB2GRAY)
+ cv.Threshold(grey, grey, THRESHOLD, 255, cv.CV_THRESH_BINARY)
+ cv.Copy(grey, grey2)
+
+ storage = cv.CreateMemStorage(0)
+ contour = cv.FindContours(grey, storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE)
+ while contour:
+ bound_rect = cv.BoundingRect(list(contour))
+ contour = contour.h_next()
+
+ pt = (bound_rect[0] + bound_rect[2]/2, bound_rect[1] + bound_rect[3]/2)
+ #cv.Circle(image, pt, 2, cv.CV_RGB(255,0,0), 1)
+ points.append(pt)
+ return points
+
+def near(p1, p2, d):
+ x,y = (p1[0]-p2[0],p1[1]-p2[1])
+ dist = math.sqrt(x**2+y**2)
+ return dist < d
+
+refpoints = getpoints(image)
+refpoints.sort(key=lambda x: x[1])
+
+oldstate = None
+
+while True:
+ image = cv.QueryFrame(camera)
+ cpoints = getpoints(image)
+ state = [False]*len(refpoints)
+ for i, rp in enumerate(refpoints):
+ for cp in cpoints:
+ if near(rp,cp,3):
+ break
+ else:
+ state[i] = True
+
+ if oldstate is not None:
+ for i,(j,k) in enumerate(zip(oldstate, state)):
+ if j != k:
+ note(NOTE_OFFSET+len(oldstate)-i, k)
+ if k:
+ print "PRESSED: %d"%i
+ else:
+ print "RELEASED: %d"%i
+ oldstate = state
+
+ cv.ShowImage("thresholded", grey2)
+ if cv.WaitKey(10)&0xfff == 27:
+ break