feat: 🔖 Deploy v1.0
Commented out rotary dialer for now
This commit is contained in:
parent
ad784673f7
commit
b6202bbaad
9
config.yaml
Normal file
9
config.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
hook_gpio: 22
|
||||||
|
rotary_gpio: 3
|
||||||
|
rotary_hold_time: 0.25
|
||||||
|
rotary_hold_repeat: true
|
||||||
|
playback_reduction: 16
|
||||||
|
beep_reduction: 24
|
||||||
|
sample_rate: 44100
|
||||||
|
buffer_size: 4096
|
||||||
|
channels: 2
|
@ -1,32 +1,39 @@
|
|||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import yaml
|
||||||
import pyaudio
|
import pyaudio
|
||||||
import time
|
|
||||||
import wave
|
import wave
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from gpiozero import Button
|
from gpiozero import Button
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
from signal import pause
|
from signal import pause
|
||||||
from pydub.scipy_effects import band_pass_filter
|
from pydub.scipy_effects import band_pass_filter
|
||||||
from pydub.effects import normalize, compress_dynamic_range, low_pass_filter, high_pass_filter
|
from pydub.effects import normalize
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from pydub.playback import play
|
from pydub.playback import play
|
||||||
|
|
||||||
hook = Button(17)
|
with open("config.yaml") as f:
|
||||||
rotaryDial = Button(18, hold_time=0.25, hold_repeat=True)
|
config = yaml.load(f, Loader=yaml.FullLoader)
|
||||||
count = 0
|
|
||||||
dialed = []
|
hook = Button(config["hook_gpio"])
|
||||||
reset_flag = False
|
# rotaryDial = Button(pin=config['rotary_gpio'], hold_time=config['rotary_hold_time'], hold_repeat=config['rotary_hold_repeat'])
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO: These globals are a temp solution for the rotary dialer, would love to not
|
||||||
|
depend on globals for this logic.
|
||||||
|
"""
|
||||||
|
# count = 0
|
||||||
|
# dialed = []
|
||||||
|
# reset_flag = False
|
||||||
|
|
||||||
# TODO: rotary encoder: special key codes trigger certain voicemails
|
|
||||||
|
|
||||||
class AudioInterface:
|
class AudioInterface:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.audio = pyaudio.PyAudio() # create pyaudio instantiation
|
self.audio = pyaudio.PyAudio()
|
||||||
self.samp_rate = 44100 # 44.1kHz sampling rate
|
self.samp_rate = config["sample_rate"]
|
||||||
self.chunk = 4096 # 2^12 samples for buffer
|
self.chunk = config["buffer_size"]
|
||||||
self.chans = 1 # 1 channel
|
self.chans = config["channels"]
|
||||||
self.format = pyaudio.paInt16 # 16-bit resolution
|
self.format = pyaudio.paInt16 # 16-bit resolution
|
||||||
self.frames = [] # raw data frames recorded from mic
|
self.frames = [] # raw data frames recorded from mic
|
||||||
|
|
||||||
@ -43,8 +50,9 @@ class AudioInterface:
|
|||||||
)
|
)
|
||||||
# loop through stream and append audio chunks to frame array
|
# loop through stream and append audio chunks to frame array
|
||||||
try:
|
try:
|
||||||
|
# TODO: either pass hook as object into class, or figure out another cleaner solution
|
||||||
while hook.is_pressed:
|
while hook.is_pressed:
|
||||||
data = self.stream.read(self.chunk, exception_on_overflow = True) # Set to False when live
|
data = self.stream.read(self.chunk, exception_on_overflow=True)
|
||||||
self.frames.append(data)
|
self.frames.append(data)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("Done recording")
|
print("Done recording")
|
||||||
@ -65,11 +73,12 @@ class AudioInterface:
|
|||||||
self.stream.write(data)
|
self.stream.write(data)
|
||||||
data = self.wf.readframes(self.chunk)
|
data = self.wf.readframes(self.chunk)
|
||||||
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
# stop the stream, close it, and terminate the pyaudio instantiation
|
# stop the stream
|
||||||
self.stream.stop_stream()
|
self.stream.stop_stream()
|
||||||
|
# close it
|
||||||
self.stream.close()
|
self.stream.close()
|
||||||
|
# terminate the pyaudio instantiation
|
||||||
self.audio.terminate()
|
self.audio.terminate()
|
||||||
|
|
||||||
def close(self, outputFile):
|
def close(self, outputFile):
|
||||||
@ -80,83 +89,123 @@ class AudioInterface:
|
|||||||
wavefile.setframerate(self.samp_rate)
|
wavefile.setframerate(self.samp_rate)
|
||||||
wavefile.writeframes(b"".join(self.frames))
|
wavefile.writeframes(b"".join(self.frames))
|
||||||
|
|
||||||
|
|
||||||
def postProcess(self, outputFile):
|
def postProcess(self, outputFile):
|
||||||
source = AudioSegment.from_file(outputFile + ".wav", format="wav")
|
"""
|
||||||
|
TODO: Evaluate whether this is worthwhile...
|
||||||
|
"""
|
||||||
|
source = AudioSegment.from_wav(outputFile + ".wav")
|
||||||
|
|
||||||
print("Filtering...")
|
print("Filtering...")
|
||||||
filtered = band_pass_filter(source, 200, 15000)
|
filtered = band_pass_filter(source, 300, 10000)
|
||||||
print("Normalizing...")
|
print("Normalizing...")
|
||||||
normalized = normalize(filtered)
|
normalized = normalize(filtered)
|
||||||
|
|
||||||
# print("Compress Dynamic Range")
|
# print("Compress Dynamic Range")
|
||||||
# compressed = compress_dynamic_range(normalized)
|
# compressed = compress_dynamic_range(normalized)
|
||||||
|
|
||||||
print("Exporting normalized")
|
print("Exporting normalized")
|
||||||
normalized.export(outputFile + "normalized.mp3", format="mp3")
|
normalized.export(outputFile + "normalized.wav", format="wav")
|
||||||
|
|
||||||
# print("Exporting compressed")
|
# print("Exporting compressed")
|
||||||
# compressed.export(outputFile + "compressed.mp3", format="mp3")
|
# compressed.export(outputFile + "compressed.mp3", format="mp3")
|
||||||
|
|
||||||
print("Finished...")
|
print("Finished...")
|
||||||
# Effects.apply_gain_stereo(audio_segment, 3, 3)
|
|
||||||
|
|
||||||
|
|
||||||
def offHook():
|
def offHook():
|
||||||
audioInterface = AudioInterface()
|
|
||||||
print("Phone off hook, ready to begin!")
|
print("Phone off hook, ready to begin!")
|
||||||
# wait a second for user to place phone to ear
|
# if dialed and dialed[0] == 0:
|
||||||
time.sleep(1)
|
audioInterface = AudioInterface()
|
||||||
|
|
||||||
# playback voice message through speaker
|
# playback voice message through speaker
|
||||||
print("Playing voicemail message...")
|
print("Playing voicemail message...")
|
||||||
# audioInterface.play(os.getcwd() + "/sounds/voicemail.wav")
|
play(
|
||||||
play(AudioSegment.from_wav(os.getcwd() + "/sounds/voicemail.wav"))
|
AudioSegment.from_wav(
|
||||||
|
os.path.dirname(os.path.abspath("rotaryGuestBook.py"))
|
||||||
|
+ "/sounds/voicemail.wav"
|
||||||
|
)
|
||||||
|
- config["playback_reduction"]
|
||||||
|
)
|
||||||
|
|
||||||
# start recording beep
|
# start recording beep
|
||||||
print("Playing beep...")
|
print("Playing beep...")
|
||||||
# audioInterface.play(os.getcwd() + "/sounds/beep.wav")
|
play(
|
||||||
play(AudioSegment.from_file(os.getcwd() + "/sounds/beep.wav", format="wav") - 16)
|
AudioSegment.from_wav(
|
||||||
|
os.path.dirname(os.path.abspath("rotaryGuestBook.py")) + "/sounds/beep.wav"
|
||||||
|
)
|
||||||
|
- config["beep_reduction"]
|
||||||
|
)
|
||||||
|
|
||||||
# now, while phone is not off the hook, record audio from the microphone
|
# now, while phone is not off the hook, record audio from the microphone
|
||||||
print("recording")
|
print("recording")
|
||||||
audioInterface.record()
|
audioInterface.record()
|
||||||
audioInterface.stop()
|
audioInterface.stop()
|
||||||
outputFile = os.getcwd() + "/recordings/" + f"{datetime.now().isoformat()}"
|
outputFile = (
|
||||||
|
os.path.dirname(os.path.abspath("rotaryGuestBook.py"))
|
||||||
|
+ "/recordings/"
|
||||||
|
+ f"{datetime.now().isoformat()}"
|
||||||
|
)
|
||||||
audioInterface.close(outputFile + ".wav")
|
audioInterface.close(outputFile + ".wav")
|
||||||
print("finished recording")
|
print("finished recording")
|
||||||
print("spawn postProcessing thread")
|
|
||||||
Process(target=audioInterface.postProcess, args=(outputFile,)).start()
|
"""
|
||||||
|
post processing
|
||||||
|
"""
|
||||||
|
# print("spawn postProcessing thread")
|
||||||
|
# Process(target=audioInterface.postProcess, args=(outputFil e,)).start()
|
||||||
|
|
||||||
|
"""
|
||||||
|
rotary dialer special messages
|
||||||
|
"""
|
||||||
|
# if dialed[0:3] == [9,2,7]:
|
||||||
|
# # play special vm
|
||||||
|
# play(AudioSegment.from_wav(os.path.dirname(os.path.abspath("rotaryGuestBook.py")) + "/sounds/927.wav") - config['playback_reduction'])
|
||||||
|
|
||||||
|
# elif dialed[0:4] == [5,4,5,3]:
|
||||||
|
# # play special vm
|
||||||
|
# play(AudioSegment.from_wav(os.path.dirname(os.path.abspath("rotaryGuestBook.py")) + "/sounds/beep.wav") - config['beep_reduction'])
|
||||||
|
|
||||||
|
|
||||||
def onHook():
|
def onHook():
|
||||||
print("Phone on hook. Sleeping...")
|
print("Phone on hook. Sleeping...")
|
||||||
|
# print("Resetting dial list")
|
||||||
|
# global dialed
|
||||||
|
# dialed = []
|
||||||
|
# reset_pulse_counter()
|
||||||
|
|
||||||
|
|
||||||
def dialing():
|
# def dialing():
|
||||||
global count, reset_flag
|
# if hook.is_pressed:
|
||||||
count+=1
|
# global count, reset_flag
|
||||||
print(f"dialing, increment count: {count}")
|
# count+=1
|
||||||
reset_flag = False
|
# print(f"dialing, increment count: {count}")
|
||||||
|
# reset_flag = False
|
||||||
|
|
||||||
def reset():
|
# def reset_pulse_counter():
|
||||||
global count, reset_flag
|
# global count, reset_flag
|
||||||
count = 0
|
# count = 0
|
||||||
toggle = False
|
# print(f"reset count: {count}")
|
||||||
print(f"reset count: {count}")
|
# reset_flag = True
|
||||||
reset_flag = True
|
|
||||||
|
|
||||||
|
|
||||||
def held():
|
# def held():
|
||||||
if(not reset_flag):
|
# if not reset_flag:
|
||||||
print("holding")
|
# print("holding")
|
||||||
print(count)
|
# print(count)
|
||||||
global dialed
|
# global dialed
|
||||||
if (count == 10):
|
# if (count == 10):
|
||||||
dialed.append(0)
|
# dialed.append(0)
|
||||||
else:
|
# else:
|
||||||
dialed.append(count)
|
# dialed.append(count)
|
||||||
print(f"number dialed: {dialed}")
|
# print(f"number dialed: {dialed}")
|
||||||
reset()
|
# offHook()
|
||||||
|
# reset_pulse_counter()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
rotaryDial.when_pressed = dialing
|
# rotaryDial.when_pressed = dialing
|
||||||
rotaryDial.when_held = held
|
# rotaryDial.when_held = held
|
||||||
|
|
||||||
hook.when_pressed = offHook
|
hook.when_pressed = offHook
|
||||||
hook.when_released = onHook
|
hook.when_released = onHook
|
||||||
pause()
|
pause()
|
||||||
|
Loading…
Reference in New Issue
Block a user