Detects sound and sets GPIO - python

I am looking for a solution that detects sound and sets GPIO21 to low and GPIO21 to high, after 5 minutes when there is no sound.
I need it for a streamer (Raspberry Pi) that will run shairport-sync, tidal-connect and spotify. When sound is detected, GPIO should trigger my amplifier.
Unfortunately I can not code python, so I hope someone can help

#SolveltPlanet
It is disabled via #dtparam=audio=on and I have Python 2.7.16 installed. Here is aplay -l
**** List of PLAYBACK Hardware Devices ****
card 1: AUDIO [SMSL USB AUDIO], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0

I think you might find this link helpful: Detecting audio. You shouldn't need all of the code in that answer, just the part on detecting silence.
I believe you can use the python gpiozero library for using the GPIO ports. You should be able to treat it as an LED.
import gpiozero #For GPIO
import time #To sleep
###REPLACE THIS WITH YOUR OWN FUNCTION (Like the one I posted in the above link)###
def is_silent():
return True
pin = gpiozero.LED(21) #Set up the GPIO pin
pin.on() #Turn it on
seconds_since_sound = 300 #Set seconds since last sound to high
while(True):
if(is_silent): #Check if there is no sounds
if(seconds_since_sound >= 300): #If there is no sounds and it has been more than 5 mins since the last sound
pin.on() #Turn on
else:
seconds_since_sound += 1 #Otherwise increment by a second
time.sleep(1) #Sleep for a second
else:
seconds_since_sound = 0 #If there is a sound then set timer to 0
pin.off() #Turn off
Unfortunately I am unable to test if the code works as I do not have access to a raspberry pi.
It looks like the silence detection does not work in python 3.
EDIT:
It looks like you can record the soundcard on some devices using this line of code:
import pyaudio #import pyaudio
p = pyaudio.PyAudio() #setup pyaudio
stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, output=True, frames_per_buffer=CHUNK_SIZE, input_device_index=2) #open pyaudio stream
snd_data = array('h', stream.read(CHUNK_SIZE)) #Capture data (should be done in while loop)
return (max(snd_data) > threshold) #Check if data is louder than threshold
(Change the input device index to point to the output of your sound card)
Once again, I am unable to test if this works as it only runs of python 2. It uses pyaudio.

Related

Trying to record audio whilst a gpio input is high in scipy

I am trying to make wedding guest answer phone for my sister. The basic idea of these things is you pick up the handset, hear a message from the host, leave you own, replace the handset, and the recording stops and saves. I have set all of the hardware up fine, it works, but as I have essentially no experience with coding getting all of the individual aspects to work is my issue.
For the recording aspect scipy seems to work the best, I have been using this for 5 second test recordings.
import sounddevice as sd
from scipy.io.wavfile import write
import wavio as wv
import uuid
freq = 44100
duration = 5
recording = sd.rec(int(duration * freq),
samplerate=freq, channels=2)
sd.wait()
write("recording0_"+str(uuid.uuid4())+".wav", freq, recording)
The main issue is these messages are only 5 seconds, I don't know how to make them start recording after the host message and stop when the handset is replaced.
The following is the code that I have been using to play a test for the host message when the handset is picked up.
import RPi.GPIO as gpio
import pygame
gpio.setmode(gpio.BCM)
gpio.setup(23, gpio.IN, pull_up_down=gpio.PUD_UP)
gpio.setwarnings(False)
def rising(channel):
gpio.remove_event_detect(23)
print ('Button up')
pygame.mixer.init()
sound = pygame.mixer.Sound('/home/pi/Documents/E and R/test1.wav')
playing = sound.play()
while playing.get_busy():
pygame.time.delay(100)
gpio.add_event_detect(23, gpio.FALLING, callback=falling, bouncetime=10)
def falling(channel):
gpio.remove_event_detect(23)
print ('Button down')
gpio.add_event_detect(23, gpio.RISING, callback=rising, bouncetime=10)
gpio.add_event_detect(23, gpio.FALLING, callback=falling, bouncetime=10)
try:
raw_input()
except KeyboardInterrupt:
gpio.cleanup()
gpio.cleanup()
There are a few problems with this, I have tried changing the order of various aspects and either when you lift the handset and the audio is played it doesn't read if the handset is replaced while the audio is playing. Or in another version if you tap the handset switch a bunch of times it layers copies of the audio on top of each other.
Also I know that raw_input() is not used in python 3 but if I just use input() the code doesn't work and if I omit the whole section it doesn't work.
Basically, I'm illiterate and any help smashing this all together and showing me how to get audio recordings for an in-determinant length of time would be greatly appreciated.
Also if this helps I'm using a Raspberry pi 4 and Python 3.9.2.

How can I make the Raspberry Pico not automount as USB storage while using Circuit Python

I am using Circuit Python on a Raspberry Pi Pico to give me hardware buttons for keyboard shortcuts. I am using Circuit Python as opposed to MicroPython because it has the USB_HID library.
I don't want the Pico to automatically mount as USB storage when being plugged in. I just want it to act as a HID device. I am aware that I can write a boot.py script in addition to a code.py but I can't find anywhere online what to put in this which would prevent it from mounting as a USB device. I also still want it to mount as USB sometimes (when a button is pressed/GPIO pin is connected) so there is a still a way for me to change the code on the device.
Is this possible? And, if so, what should the boot.py look like to only mount when a certain GPIO pin is connected?
I recently came across a need to do the same that you are looking for, and after a decent rabbit hole, have determined that it can't be done at this time.
https://github.com/adafruit/circuitpython/issues/1015
Looks like the request was opened a few years ago and is still listed as open.
I am not sure if running a pi zero in "gadget" mode can accomplish this or not, but may be worth a look
The code below is what I use. Roughly, it checks to see if a button connected to one of the Pico's IO pins. If the button is pressed when the cable is plugged in, then it mounts as a USB drive. If the button is not pressed, it's not mounted:
import storage
import board, digitalio
# If not pressed, the key will be at +V (due to the pull-up).
# https://learn.adafruit.com/customizing-usb-devices-in-circuitpython/circuitpy-midi-serial#circuitpy-mass-storage-device-3096583-4
button = digitalio.DigitalInOut(board.GP2)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
# Disable devices only if button is not pressed.
if button.value:
print(f"boot: button not pressed, disabling drive")
storage.disable_usb_drive()
This was adapted from examples on Adafruit's site
Here's a good HID guide:
https://learn.adafruit.com/circuitpython-essentials/circuitpython-hid-keyboard-and-mouse
Here's the HID example:
import time
import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode
# A simple neat keyboard demo in CircuitPython
# The pins we'll use, each will have an internal pullup
keypress_pins = [board.A1, board.A2]
# Our array of key objects
key_pin_array = []
# The Keycode sent for each button, will be paired with a control key
keys_pressed = [Keycode.A, "Hello World!\n"]
control_key = Keycode.SHIFT
# The keyboard object!
time.sleep(1) # Sleep for a bit to avoid a race condition on some systems
keyboard = Keyboard(usb_hid.devices)
keyboard_layout = KeyboardLayoutUS(keyboard) # We're in the US :)
# Make all pin objects inputs with pullups
for pin in keypress_pins:
key_pin = digitalio.DigitalInOut(pin)
key_pin.direction = digitalio.Direction.INPUT
key_pin.pull = digitalio.Pull.UP
key_pin_array.append(key_pin)
# For most CircuitPython boards:
led = digitalio.DigitalInOut(board.D13)
# For QT Py M0:
# led = digitalio.DigitalInOut(board.SCK)
led.direction = digitalio.Direction.OUTPUT
print("Waiting for key pin...")
while True:
# Check each pin
for key_pin in key_pin_array:
if not key_pin.value: # Is it grounded?
i = key_pin_array.index(key_pin)
print("Pin #%d is grounded." % i)
# Turn on the red LED
led.value = True
while not key_pin.value:
pass # Wait for it to be ungrounded!
# "Type" the Keycode or string
key = keys_pressed[i] # Get the corresponding Keycode or string
if isinstance(key, str): # If it's a string...
keyboard_layout.write(key) # ...Print the string
else: # If it's not a string...
keyboard.press(control_key, key) # "Press"...
keyboard.release_all() # ..."Release"!
# Turn off the red LED
led.value = False
time.sleep(0.01) ```
The example only prints Hello World, so it's not very useful, but it's a good base to mod.
i try this and it work
https://learn.adafruit.com/circuitpython-essentials/circuitpython-storage
it not write to code.pi but in boot.py you have to create the file first.

Controlling Stepper motors and Camera simultaneously

what is the best way to control a stepper motor and camera simultaneously?
Suppose the camera is placed on a linear stage (stepper motor) and I want to move the stage in 1 mm steps and capture a frame at the end of each step. Both devices (Camera and the stage) are connected to my computer (Ubuntu 18.04.3 LTS) via 2 different USB 2.0 ports.
My script for the camera looks something like:
def camera():
...
...
...
while(True):
cv2.imshow('live', frame)
ueye.is_ExitCamera(hCam2)
cv2.destroyAllWindows()
if __name__ == "__main__":
camera()
and outputs live broadcast from the camera.
For the motor something like:
i = 0
while i < 6: # Move 6 times
stepper.Move(0.5) # Moves forward by 0.5 mm
time.sleep(1) # Sleeps for a second
i += 1
time.sleep(2)
print("\nProcess End\n")
close() # closes port
and moves and sleeps as desired.
Both scripts run sucessfully when executed seperately. However, how do I combine these scripts so that I can take a picture at the end of each step? For the example adressed above for moving 6 times, I want to get 6 images at the end, captured at the end of each step. Should one use multithreading, multiprocessing?... Both devices are connected to my computer via 2 seperate USB 2.0 ports. I'm not a beginner in programming, but not an expert either so any suggestions will be kindly appreciated.
It there a reason that you can't call some function that captures an image on each step?
# import modules for camera and stepper control
def step_and_capture(steps=6):
images = []
for x in range(steps):
stepper.Move(0.5)
image = cam_capture_method() # returns a photo or it could write to somewhere
time.sleep(1)
# save the images to folder?
if __name__ == "__main__":
step_and_capture()

Psychopy MovieStim3: pausing errors

I am trying to follow the MovieStim3 pausing example as outlined here:
MoviePause.py
I am using the same code as this example, except I am using my own movie file.
print('orig movie size=' + str(mov.size))
print('duration=%.2fs' % mov.duration)
globalClock = core.Clock()
# play 100 frames normally
for frameN in range(100):
mov.draw()
win.flip()
# pause stops sound and prevents frame from advancing
mov.pause()
for frameN in range(100):
mov.draw()
win.flip()
# frame advance and audio continue
mov.play()
while globalClock.getTime() < (mov.duration + 1.0):
mov.draw()
win.flip()
win.close()
core.quit()
The issue I'm having is that the video pauses fine, but when it starts playing again, the video and audio are not synchronized anymore. It appears as though the audio pauses and restarts fine, but the video shows a burst of fast frames before going at the proper speed. Its almost as if the video is trying to 'catch up' to a timer, but I haven't been able to figure it out.
Sounds like a player issue, some incompatibility between moviepy and your movie format. Try to convert the movie file to some other format such as h264 with ffmpeg and try again.

How to generate sound signal through a GPIO pin on BeagleBone

I am looking for pointers/tips on how to generate a synthesized sound signal on the BeagleBone akin to watch the tone() function would return on a Arduinos. Ultimately, I'd like to connect a piezo or a speaker on a GPIO pin and hear a sound wave out of it. Any pointers?
This is how I managed to solve this question on the Beaglebone using Python and PyBBIO:
#!/usr/bin/python
# Circuit:
# * A Piezo is connected to pin 12 on header P8. - GPIO1_12
# * A LED is connected to pin 14 on header P8. - GPIO0_26
# * A button is connected to pin 45 on header P8. - GPIO2_6
# Use a pull-down resistor (around 10K ohms) between pin 45 and ground.
# 3.3v for the other side of the button can be taken from pins 3 or 4
# on header P9. Warning: Do not allow 5V to go into the GPIO pins.
# * GND - pin 1 or 2, header P9.
def setup(): # this function will run once, on startup
pinMode(PIEZO, OUTPUT) # set up pin 12 on header P8 as an output - Piezo
pinMode(LED, OUTPUT) # set up pin 14 on header P8 as an output - LED
pinMode(BUTTON, INPUT) # set up pin 45 on header P8 as an input - Button
def loop(): # this function will run repeatedly, until user hits CTRL+C
if (digitalRead(BUTTON) == HIGH):
# was the button pressed? (is 3.3v making it HIGH?) then do:
buzz()
delay(10) # don't "peg" the processor checking pin
def delay(j): #need to overwrite delay() otherwise, it's too slow
for k in range(1,j):
pass
def buzz(): #this is what makes the piezo buzz - a series of pulses
# the shorter the delay between HIGH and LOW, the higher the pitch
limit = 500 # change this value as needed;
# consider using a potentiometer to set the value
for j in range(1, limit):
digitalWrite(PIEZO, HIGH)
delay(j)
digitalWrite(PIEZO, LOW)
delay(j)
if j==limit/2:
digitalWrite(LED, HIGH)
digitalWrite(LED, LOW) # turn it off
run(setup, loop)
Check out this page. From userland (e.g. python) you can use set a pin to high or low by writing to the correct sysfs file in /sys/class/gpio.
The GPIO pins of the AM3359 are low-voltage and with insufficient driver strength to directly drive any kind of transducer. You would need to build a small circuit with a op-amp, transistor or FET to do this.
Once you've done this, you'd simply set up a timer loop to change the state of the GPIO line at the required frequency.
By far the quickest and easiest way of getting audio from this board is with a USB Audio interface.

Categories

Resources