diff --git a/client/pyscripts/theremin.py b/client/pyscripts/theremin.py new file mode 100644 index 000000000..a84ff3adf --- /dev/null +++ b/client/pyscripts/theremin.py @@ -0,0 +1,78 @@ +#!/usr/bin/python3 + +### Parameters +# Sound output parameters +volume = 1.0 +sample_buf_size = 44 +sampling_freq = 44100 #Hz + +# Frequency generator parameters +min_freq = 200 #Hz +max_freq = 2000 #Hz + +# Proxmark3 parameters +pm3_client="/usr/local/bin/proxmark3" +pm3_reader_dev_file="/dev/ttyACM0" +pm3_tune_cmd="hf tune" + + +### Modules +import numpy +import pyaudio +from select import select +from subprocess import Popen, DEVNULL, PIPE + + +### Main program +p = pyaudio.PyAudio() + +# For paFloat32 sample values must be in range [-1.0, 1.0] +stream = p.open(format=pyaudio.paFloat32, + channels=1, + rate=sampling_freq, + output=True) + +# Initial voltage to frequency values +min_v = 100.0 +max_v = 0.0 +v = 0 +out_freq = min_freq + +# Spawn the Proxmark3 client +pm3_proc = Popen([pm3_client, pm3_reader_dev_file, "-c", pm3_tune_cmd], + bufsize=0, env={}, stdin=DEVNULL, stdout=PIPE, stderr=DEVNULL) +mv_recbuf = "" + +# Read voltages from the Proxmark3, generate the sine wave, output to soundcard +sample_buf = [0.0 for x in range(0, sample_buf_size)] +i = 0 +sinev = 0 +while True: + + # Read Proxmark3 client's stdout and extract voltage values + if(select([pm3_proc.stdout], [], [], 0)[0]): + + b = pm3_proc.stdout.read(256).decode("ascii") + for c in b: + if c in "0123456789 mV": + mv_recbuf += c + else: + mv_recbuf = "" + if mv_recbuf[-3:] == " mV": + v = int(mv_recbuf[:-3]) / 1000 + if v < min_v: + min_v = v - 0.001 + if v > max_v: + max_v = v + + # Recalculate the audio frequency to generate + out_freq = (max_freq - min_freq) * (max_v - v) / (max_v - min_v) + min_freq + + # Generate the samples and write them to the soundcard + sinevs = out_freq / sampling_freq * numpy.pi * 2 + sample_buf[i] = sinev + sinev += sinevs + sinev = sinev if sinev < numpy.pi * 2 else sinev - numpy.pi * 2 + i = (i + 1) % sample_buf_size + if not i: + stream.write((numpy.sin(sample_buf) * volume).astype(numpy.float32).tobytes())