Skip to content
Snippets Groups Projects
Commit f6b9c9ab authored by dronus's avatar dronus
Browse files

SOUNDOFWOOD wood scan to music interpreter with RaspiCam input and Jack MIDI output

parents
No related branches found
No related tags found
No related merge requests found
{
"camera_warmup_time": 2.5,
"resolution": [640, 480],
"fps": 20,
"contrast_limit":3.0,
"threshold": 150,
"pitch_min":20,
"pitch_range":88
}
<!DOCTYPE patchbay>
<patchbay name="jack_patching" version="0.4.4">
<output-sockets>
<socket client="bristol" type="jack-audio" exclusive="off" name="bristol 1">
<plug>out_left</plug>
<plug>out_right</plug>
</socket>
<socket client="Woodsound Scanner" type="jack-midi" exclusive="off" name="Woodsound Scanner 1">
<plug>output</plug>
</socket>
</output-sockets>
<input-sockets>
<socket client="system" type="jack-audio" exclusive="off" name="system 1">
<plug>playback_1</plug>
<plug>playback_2</plug>
</socket>
<socket client="bristol" type="jack-midi" exclusive="off" name="bristol 1">
<plug>midi_in</plug>
</socket>
</input-sockets>
<slots/>
<cables>
<cable type="jack-audio" output="bristol 1" input="system 1"/>
<cable type="jack-midi" output="Woodsound Scanner 1" input="bristol 1"/>
</cables>
</patchbay>
#!/usr/bin/python3
# import the necessary packages
#from pyimagesearch.tempimage import TempImage
from psonic import *
import math
from picamera.array import PiRGBArray
from picamera import PiCamera
import argparse
import warnings
import datetime
#import dropbox
import imutils
import json
import time
import cv2
import numpy as np
import os
from threading import Timer
import jack
# First 4 bits of status byte:
NOTEON = 0x9
NOTEOFF = 0x8
client = jack.Client("Woodsound Scanner")
outport = client.midi_outports.register("output")
out_queue=[]
@client.set_process_callback
def process(frames):
outport.clear_buffer()
while out_queue:
outport.write_midi_event(0,out_queue.pop())
client.activate()
stats=""
mainKeys = [C3,D3,E3,F3,G3,A3,B3,C5,D5,E5,F5,G5,A5,B5]
#timer class:
class aTimer():
def __init__(self,t,hFunction):
self.t=t
self.hFunction = hFunction
self.thread = Timer(self.t,self.handle_function)
def handle_function(self):
self.hFunction()
self.thread = Timer(self.t,self.handle_function)
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
def sectimerevent():
global stats
stats=getCPUtemperature()
def getCPUtemperature():
# res = os.popen('vcgencmd measure_temp').readline()
# return(res.replace("temp=","").replace("'C\n",""))
res=os.popen('/home/pi/getcpufreq.sh').readline()
return res
#a,b: center of circle, r:radius
def inside_circle(x, y, a, b, r):
return (x - a)*(x - a) + (y - b)*(y - b) < r*r
class SmoothedFpsCalculator:
"""
Provide smoothed frame per second calculation.
"""
def __init__(self, alpha=0.1):
self.t = time.time()
self.alpha = alpha
self.sfps = None
def __call__(self):
t = time.time()
d = t - self.t
self.t = t
fps = 1.0 / d
if self.sfps is None:
self.sfps = fps
else:
self.sfps = fps * self.alpha + self.sfps * (1.0 - self.alpha)
return self.sfps
use_synth(PROPHET)
print("testing pisonic output")
q=[C3,D3,E3]
play(q, attack=0.5, decay=1, sustain_level=0.5, sustain=2, release=2)
time.sleep(2)
q=[F3,G3,A3]
play(q, attack=0.5, decay=1, sustain_level=0.5, sustain=2, release=2)
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-c", "--conf", required=True,
help="path to the JSON configuration file")
args = vars(ap.parse_args())
# filter warnings, load the configuration and initialize the Dropbox
# client
warnings.filterwarnings("ignore")
conf = json.load(open(args["conf"]))
client = None
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = tuple(conf["resolution"])
camera.framerate = conf["fps"]
camera.shutter_speed=1000000
rawCapture = PiRGBArray(camera, size=tuple(conf["resolution"]))
# allow the camera to warmup, then initialize the average frame, last
# uploaded timestamp, and frame motion counter
print("[INFO] warming up...")
time.sleep(conf["camera_warmup_time"])
avg = None
lastUploaded = datetime.datetime.now()
motionCounter = 0
#t = aTimer(1,sectimerevent)
#t.start()
pixel_count=0
sfps = SmoothedFpsCalculator()
num_keys=conf["pitch_range"]
last_line_frame=np.zeros((1,num_keys))
# capture frames from the camera
clahe=cv2.createCLAHE(clipLimit=conf["contrast_limit"])
for f in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
# grab the raw NumPy array representing the image and initialize
# the timestamp and occupied/unoccupied text
frame = f.array
timestamp = datetime.datetime.now()
text = "Unoccupied"
crop_frame=frame[190:210,0:640]
crop_frame = cv2.cvtColor(crop_frame, cv2.COLOR_BGR2GRAY)
crop_frame=clahe.apply(crop_frame)
# crop_frame=cv2.equalizeHist(crop_frame)
# retval,crop_frame=cv2.threshold(crop_frame,25,255,cv2.THRESH_BINARY)
line_frame=crop_frame[10:11,5:635]
line_frame=cv2.resize(line_frame, (num_keys+2,1), interpolation = cv2.INTER_AREA)
line_frame_2=line_frame[0:1,1:num_keys+1]
retval,line_frame=cv2.threshold(line_frame_2,conf["threshold"],255,cv2.THRESH_BINARY)
index=0
for pixel in np.nditer(line_frame):
last_pixel=last_line_frame[0,index]
if pixel==0 and last_pixel>0:
packet=((NOTEON <<4), conf["pitch_min"]+index, 99)
out_queue.append(packet)
pixel_count+=1
if pixel>0 and last_pixel==0:
packet=((NOTEOFF<<4), conf["pitch_min"]+index, 99)
out_queue.append(packet)
pixel_count-=1
index+=1
print("Pixels on: "+str(pixel_count))
last_line_frame=np.copy(line_frame)
# cv2.putText(frame, '%0.2f fpsu, %s' %(sfps(),stats), (10, frame.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 1.0, 255)
cv2.imshow("Security Feed", crop_frame)
cv2.imshow("Security Feed 2", line_frame)
key = cv2.waitKey(1) & 0xFF
# if the `q` key is pressed, break from the lop
if key == ord("q"):
break
# clear the stream in preparation for the next frame
rawCapture.truncate(0)
run.sh 0 → 100755
#!/bin/bash
cd `dirname $0`
export DISPLAY=:0
startBristol -mini -voices 6 &
./linescan.py -c conf.json &
sleep 5
qjackctl &
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment