Add random phrases when an optional pi camera detects motion.
Fix LED paths for more recent pi-image operating systems. FossilOrigin-Name: 95bda0bf25a4c8760c07217545106e4a5116a2a6e01463d5189551eb83bfa0f7
This commit is contained in:
parent
65ac4ce493
commit
74bfdfac57
9 changed files with 135 additions and 19 deletions
|
|
@ -4,23 +4,35 @@
|
|||
---
|
||||
logging:
|
||||
__default__: info (color)
|
||||
theremin: debug (color)
|
||||
# theremin: debug (color)
|
||||
# gpio: debug (color)
|
||||
|
||||
# See: https://pinout.xyz/
|
||||
#
|
||||
theremin:
|
||||
# See: https://pinout.xyz/ - GPIO labels, not physical
|
||||
pitch_trigger: 27
|
||||
pitch_echo: 22
|
||||
gain_trigger: 23
|
||||
gain_echo: 24
|
||||
|
||||
# Fine tune range sensors
|
||||
distance_max: 2
|
||||
# sample_interval: 0.5
|
||||
# slew: 5
|
||||
|
||||
# Speech
|
||||
startup_message: Hello. I'm Maude the bod.
|
||||
use_motion: true
|
||||
motion_messages:
|
||||
- Lets make beautiful music together.
|
||||
- Oh yeah!
|
||||
- Yes yes yes yes yessss yyyyyyyyyyyyyyyyyyyyyyyy yes!
|
||||
- oooooooooooooooooooooookay!
|
||||
- Let's rock.
|
||||
|
||||
# Alter synth sounds from defaults.
|
||||
cancel_after: 3
|
||||
startup_message: Hello. I'm Maude the bod. Lets make beautiful music together.
|
||||
# font: /usr/share/sounds/sf2/FluidR3_GM.sf2
|
||||
# glide: 1
|
||||
# slew: 5
|
||||
# sample_interval: 0.5
|
||||
# reverb: false
|
||||
# chorus: false
|
||||
# font_index: 2
|
||||
|
|
|
|||
0
theremin/lib/gpio.rb
Executable file → Normal file
0
theremin/lib/gpio.rb
Executable file → Normal file
47
theremin/lib/theremin.rb
Executable file → Normal file
47
theremin/lib/theremin.rb
Executable file → Normal file
|
|
@ -8,6 +8,7 @@ require 'loggability'
|
|||
require 'gpio'
|
||||
require 'fluidsynth'
|
||||
require 'open3'
|
||||
require 'socket'
|
||||
|
||||
|
||||
# A class that coordinates GPIO events and translates
|
||||
|
|
@ -130,6 +131,12 @@ class Theremin
|
|||
|
||||
## ESpeak TTL options.
|
||||
setting :espeak_flags, default: %w[ -k20 -v f5 -s 160 -a 150 ]
|
||||
|
||||
## Watch for camera motion?
|
||||
setting :use_motion, default: false
|
||||
|
||||
## A list of phrases to randomly say when motion is detected.
|
||||
setting :motion_messages, default: []
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -163,6 +170,9 @@ class Theremin
|
|||
# An IO to stream to espeak.
|
||||
attr_reader :speech_io
|
||||
|
||||
# A TCPServer for motion IPC
|
||||
attr_reader :motion_socket
|
||||
|
||||
# Is this Theremin currently running?
|
||||
attr_reader :running
|
||||
|
||||
|
|
@ -181,10 +191,11 @@ class Theremin
|
|||
self.chorus( self.class.chorus )
|
||||
self.instrument( self.class.font_index, self.class.instrument_index )
|
||||
|
||||
self.speak( self.class.startup_message ) if self.class.startup_message
|
||||
@threads << self.note_thread
|
||||
@threads << self.gain_thread
|
||||
@threads << self.motion_thread if self.class.use_motion
|
||||
self.led( :green )
|
||||
self.speak( self.class.startup_message ) if self.class.startup_message
|
||||
self.log.warn "Waiting for interaction, or ctrl-c to exit."
|
||||
@threads.map( &:join )
|
||||
end
|
||||
|
|
@ -196,14 +207,15 @@ class Theremin
|
|||
@running = false
|
||||
self.pins.each {|pin| self.class.send( pin ).unexport rescue nil }
|
||||
self.synth.socket.close
|
||||
self.motion_socket.close
|
||||
self.speech_io.close if self.speech_io && !self.speech_io.closed?
|
||||
self.led( :red )
|
||||
end
|
||||
|
||||
|
||||
#########
|
||||
protected
|
||||
#########
|
||||
|
||||
#########
|
||||
protected
|
||||
#########
|
||||
|
||||
### Measure pitch distance, and manage notes sent to the synth.
|
||||
###
|
||||
|
|
@ -271,6 +283,23 @@ class Theremin
|
|||
end
|
||||
|
||||
|
||||
### Watch the motion fifo, say a random phrase when motion seen.
|
||||
###
|
||||
def motion_thread
|
||||
phrases = self.class.motion_messages
|
||||
return if phrases.empty?
|
||||
|
||||
@motion_socket = TCPServer.new( 62877 )
|
||||
return self.running_thread do
|
||||
client = @motion_socket.accept
|
||||
self.log.info "Camera motion detected."
|
||||
client.close
|
||||
self.speak( phrases.sample )
|
||||
rescue IOError
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
### Open a pipe to espeak, and wait on input.
|
||||
##
|
||||
def setup_speech
|
||||
|
|
@ -375,11 +404,11 @@ class Theremin
|
|||
def led( color )
|
||||
case color
|
||||
when :red
|
||||
File.open( '/sys/class/leds/led0/brightness', 'w' ){|l| l.puts(0) }
|
||||
File.open( '/sys/class/leds/led1/brightness', 'w' ){|l| l.puts(1) }
|
||||
File.open( '/sys/class/leds/PWR/brightness', 'w' ){|l| l.puts(1) }
|
||||
File.open( '/sys/class/leds/ACT/brightness', 'w' ){|l| l.puts(0) }
|
||||
when :green
|
||||
File.open( '/sys/class/leds/led0/brightness', 'w' ){|l| l.puts(1) }
|
||||
File.open( '/sys/class/leds/led1/brightness', 'w' ){|l| l.puts(0) }
|
||||
File.open( '/sys/class/leds/PWR/brightness', 'w' ){|l| l.puts(0) }
|
||||
File.open( '/sys/class/leds/ACT/brightness', 'w' ){|l| l.puts(1) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
0
theremin/log/main/.placeholder
Normal file
0
theremin/log/main/.placeholder
Normal file
5
theremin/log/run
Executable file
5
theremin/log/run
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
exec 2>&1
|
||||
exec svlogd ./main
|
||||
|
||||
|
|
@ -15,5 +15,7 @@ Signal.trap( "INT" ) do
|
|||
theremin.stop if theremin.running
|
||||
end
|
||||
|
||||
$stderr.sync = true
|
||||
$stdout.sync = true
|
||||
theremin.start
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue