Commit de7ae02d authored by Phyks's avatar Phyks
Browse files

Working on chorizo player, will be there soon

parent 8fd18513
*__pycache*
Chorizo.py :
====
This script allows you to play music using a chorizo (or whatever food you
like) keyboard ! See README for more info and links.
As all the other scripts in this repository, I release it under a very
permissive license. To make a long story short : do whatever you want with
this script (but try to have fun :), I don't mind. It would be cool to quote
the origin of the script if you reuse it, but you don't have to. I'd like to
be noticed of what you did cool with it (if you think it's worth). :)
Ah, I almost forgot : If by chance we ever meet and you think this script is
worth, you can buy me a soda :)
Phyks
Sound4Python.py : https://github.com/standarddeviant/sound4python
====
Note : The version of sound4python.py in this project is slightly modified (some print statements commented and a bugfix).
Copyright (C) 2013 dave.crist@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#!/usr/bin/env python3
# ============================================================================
# This script allows you to play music using a chorizo (or whatever food you
# like) keyboard ! See README for more info and links.
# As all the other scripts in this repository, I release it under a very
# permissive license. To make a long story short : do whatever you want with
# this script (but try to have fun :), I don't mind. It would be cool to quote
# the origin of the script if you reuse it, but you don't have to. I'd like to
# be noticed of what you did cool with it (if you think it's worth). :)
# Ah, I almost forgot : If by chance we ever meet and you think this script is
# worth, you can buy me a soda :)
#
# Phyks
# =============================================================================
from sound4python import sound
from multiprocessing oimport Process
import math
import serial
import sys
import getopt
def play_wave(frequency=440, nb_secs=1):
sine_wave = []
for i in range(nb_secs*framerate):
sine_wave.append(int(16384*math.sin(2*math.pi*frequency*i/framerate)))
sound(sine_wave)
serial_port = "/dev/ttyACM0"
try:
opts, args = getopt.getopt(sys.argv[1:], "hs:", ["help", "serial="])
for opt, arg in opts:
if opt in ("-h", "--help"):
print("Play music with chorizos !")
print("\nUsage : "+sys.argv[0]+" [OPTIONS]")
print("\nOptions :")
print("\t-h (--help) \t display this help message")
print("\t-s (--serial=) \t change serial port (default is " +
"/dev/tty/ACM0")
sys.exit(0)
elif opt in ("-s", "--serial"):
serial_port = arg
except getopt.GetoptError:
pass
try:
ser = serial.Serial(serial_port, 115200)
except Exception as e:
sys.exit("Error with serial port :"+str(e))
framerate = 16000
frequencies = [440, 600, 880]
gap_times = 10
p = []
for i in range(3):
processes.append(Process(target=play_wave, args=(frequencies[i], 1)))
processes[-1].start()
try:
ser.open()
except Exception as e:
sys.exit("Error while opening serial port : "+str(e))
if ser.isOpen():
try:
ser.flushInput()
ser.flushOutput()
measures = [[], [], []]
print("Calibration :")
print("Touch each chorizo electrodes before starting")
for i in range(10000):
line = ser.readline()
line = line.decode().strip("\r\n")
line = line.split(" ")
line = [int(j or 0) for j in line]
for j in range(3):
measures[j][i] = line[j]
# Get threshold
threshold = [-1, -1, -1]
for i in range(3):
gap = -1
for j in range(1, 10000):
if measures[i][j] - measures[i][j-1] > gap:
gap = measures[i][j] - measures[i][j-1]
threshold[i] = (measures[i][j]+measures[i][j-1])/2
print("Running...")
running = True
while running:
# Read line from serial
line = ser.readline()
line = line.decode().strip("\r\n")
line = line.split(" ")
line = [int(j or 0) for j in line]
for i in range(3):
if line[i] > threshold[i]:
print("Playing")
p[i].start()
p[i].join()
except Exception as e:
sys.exit("Error while handling data from serial : "+str(e))
try: import tempfile, wave, subprocess, os, signal, struct
except:
print("E: sound4python is unable to import a combination of %s"%
("tempfile, wave, subprocess, os, signal, struct"))
FNULL = open(os.devnull,'w')
def launchWithoutConsole(args,output=False):
"""Launches args windowless and waits until finished"""
startupinfo = None
if( 'STARTUPINFO' in dir(subprocess) ):
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
if( output ):
return subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,startupinfo=startupinfo, )
else:
return subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=FNULL ,stderr=FNULL, startupinfo=startupinfo)
# sound4python
def sound(itr,samprate=16000,autoscale=True,output=False):
try: import numpy as np; foundNumpy=True;
except:
foundNumpy=False;
#for now, assume 1-D iterable
mult = 1
if( autoscale ):
mult = 32767.0 / max(itr)
#mult = 128.0 / max(itr)
#create file in memory
#with tempfile.SpooledTemporaryFile() as memFile:
memFile = tempfile.SpooledTemporaryFile()
#create wave write objection pointing to memFile
waveWrite = wave.open(memFile,'wb')
waveWrite.setsampwidth(2) # int16 default
waveWrite.setnchannels(1) # mono default
waveWrite.setframerate(samprate) # 8kHz default
wroteFrames=False
#Let's try to create sound from NumPy vector
if( foundNumpy ):
if( type(itr)==np.array ):
if( itr.ndim == 1 or itr.shape.count(1) == itr.ndim - 1 ):
waveWrite.writeframes( (mult*itr.flatten()).astype(np.int16).tostring() )
wroteFrames=True
else: #we have np, but the iterable isn't a vector
waveWrite.writeframes( (mult*np.array(itr)).astype(np.int16).tostring() )
wroteFrames=True
if( not wroteFrames and not foundNumpy ):
#python w/o np doesn't have "short"/"int16", "@h" is "native,aligned short"
waveWrite.writeframes( struct.pack(len(itr)*"@h",[int(mult*itm) for itm in itr]) )
wroteFrames=True
if( not wroteFrames ):
print("E: Unable to create sound. Only 1D numpy arrays and numerical lists are supported.")
waveWrite.close()
return None
#configure the file object, memFile, as if it has just been opened for reading
memFile.seek(0)
try:
# getting here means wroteFrames == True
#print("\nAttempting to play a mono audio stream of length")
#print(" %.2f seconds (%.3f thousand samples at sample rate of %.3f kHz)"%
# ( 1.0*len(itr)/samprate , len(itr)/1000. , int(samprate)/1000.) )
p=launchWithoutConsole(['sox','-','-d'])
except:
print("E: Unable to launch sox.")
print("E: Please ensure that sox is installed and on the path.")
print("E: Try 'sox -h' to test sox installation.")
waveWrite.close()
return None
try:
p.communicate(memFile.read())
p.wait()
except:
print("E: Unable to send in-memory wave file to stdin of sox subprocess.")
waveWrite.close()
return None
#os.kill(p.pid,signal.CTRL_C_EVENT)
#end def sound(itr,samprate=8000,autoscale=True)
......@@ -15,47 +15,86 @@
# Phyks
# =============================================================================
# TODO
import wave
from sound4python import sound
from multiprocessing import Process
import math
import pyaudio
import sys
class _Getch:
"""Gets a single character from standard input. Does not echo to the
screen."""
def __init__(self):
try:
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
# Params
# ======
nChannels = 1 # Mono
sample_size = 2 # Size of a sample -> 1 = 8 bits
framerate = 44100 # Sampling frequency
length = 2 # Length in seconds
frequency = 440
level = 1
# =====
def __call__(self): return self.impl()
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
if level < 0.0 or level > 1.0:
sys.exit(1)
filename = "temp"
w = wave.open(filename, 'w')
class _GetchWindows:
def __init__(self):
import msvcrt
# Computed params
nFrames = int(length*framerate)
max_amplitude = int(2**(sample_size * 8 - 1) - 1)
amplitude = max_amplitude*level
def __call__(self):
import msvcrt
return msvcrt.getch()
w.setparams((nChannels, sample_size, framerate, nFrames,
'NONE', 'not compressed'))
getch = _Getch()
def play_wave(frequency=440, nb_secs=1.):
sine_wave = []
for i in range(math.ceil(nb_secs*framerate)+1):
sine_wave.append(int(16384*math.sin(2*math.pi*frequency*i/framerate)))
sound(sine_wave)
framerate = 16000
processes = []
frequency = 440
sine_wave = []
for i in range(min(framerate, nFrames)):
sine_wave.append(int(max_amplitude +
amplitude*math.sin(2*math.pi*frequency*i/framerate)))
print("Running... Press q to quit.")
running = True
while running:
char = getch()
if char == "q":
running = False
continue
elif char == "a":
frequency = 440
elif char == "b":
frequency = 493.88
elif char == "c":
frequency = 523.25
elif char == "d":
frequency = 587.33
elif char == "e":
frequency = 659.26
elif char == "f":
frequency = 698.46
elif char == "g":
frequency = 783.99
else:
continue
for i in range(nFrames):
sine_wave = int(amplitude*math.sin(2*math.pi*frequency*i/framerate))
data = wave.struct.pack('h', sine_wave)
# ^ h is for "short" so each value can go from -2**15 to 2**15
w.writeframesraw(data)
print("Playing "+char.upper())
processes.append(Process(target=play_wave, args=(frequency, 0.2)))
processes[-1].start()
w.close()
for i in processes:
i.join()
......@@ -46,14 +46,14 @@ try:
opts, args = getopt.getopt(sys.argv[1:], "hs:", ["help", "serial="])
for opt, arg in opts:
if opt == "-h" or opt == "-help":
if opt in ("-h", "--help"):
print("Touchless 3D tracking with color mapping")
print("\nUsage : "+sys.argv[0]+" [OPTIONS]")
print("\nTrack the position of your hand in 3D and map it " +
"in RGB space")
print("\nOptions :")
print("\t-h (--help) \t display this help message")
print("\t-s (--serial) \t change serial port (default is " +
print("\t-s (--serial=) \t change serial port (default is " +
"/dev/tty/ACM0")
sys.exit(0)
elif opt in ("-s", "--serial"):
......
......@@ -25,17 +25,17 @@ where `value1`, `value2`, `value3` are values directly proportional to the disch
You'll also find some basic Python scripts as examples on possible use of the setup.
### Colors.py
### Colors
This script represents the position of your hand in the RGB space. You can then pick a color by placing your hand at a specific point in the box of the electrodes.
### Chorizo.py
### Chorizo player
__(working on)__
A script to play music using chorizo pads as a musical keyboard. See [our website](http://hackens.org/Projets/TouchlessTracking) (french, but vids are available, more coming soon) for infos and demos.
### 3d_view.py
### 3d view
__(working on)__
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment