Pilot2AWS/Pilot2AWS.py

158 lines
6.4 KiB
Python

import boto3 # pip install boto3
import pygame # pip install pygame
import numpy as np # pip install numpy
from scipy.io.wavfile import write # pip install scipy
import time
import io
import random
import os
# -------------------------------------------------------------------
# Enter your access data and your AWS region
# -------------------------------------------------------------------
atc_aws_key = "YOUR_AWS_KEY"
atc_aws_secret = "YOUR_AWS_SECRET"
atc_aws_region = "YOUR_REGION"
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Do you want to see ATC messages in the console also?
# -------------------------------------------------------------------
atc_show_responses = True
# -------------------------------------------------------------------
# The voice model you want to use.
#
# IMPORTANT:
# Depending on the model you want, the prices are per 1m characters
# generated vary *drastically*.
# 'standard' is the cheapest, 'neural' the most expensive one.
# Depending on the model you pick, the list of voices vary also.
#
# Pricing: https://aws.amazon.com/polly/pricing/
# -------------------------------------------------------------------
atc_aws_voicemodel = 'standard'
# atc_aws_voicemodel = 'neural'
# -------------------------------------------------------------------
# Define where your Pilot2ATC conversation file is located
# This file can be anywhere and have any name - just make sure you
# put in the correct absolute path into this variable.
# -------------------------------------------------------------------
atc_pilot2atc_log = "M:\\Developer\\Projects\\Pilot2AWS\\test.txt"
# -------------------------------------------------------------------
# NO TRESPASSING BEYOND THIS POINT
# -------------------------------------------------------------------
os.system("cls")
print(" ")
print(" ---------------------------------------------- ")
print(" Pilot2AWS")
print(" Making Pilot2ATC sound more natural")
print(" ---------------------------------------------- ")
print(" Developed by MarStrMind")
print(" License: MIT")
print(" ---------------------------------------------- ")
print(" Using file: " + atc_pilot2atc_log)
print(" ---------------------------------------------- ")
print(" ")
# The voice names available for playback, depending on the model
# Of course, you can remove any that you do not like
# Sources for voice names:
# - https://docs.aws.amazon.com/polly/latest/dg/neural-voices.html
# - https://docs.aws.amazon.com/polly/latest/dg/standard-voices.html
atc_voices = None
if atc_aws_voicemodel == "standard":
atc_voices = ["Nicole", "Russell", "Amy", "Emma", "Brian", "Aditi", "Raveena", "Joanna", "Kendra", "Kimberly", "Salli", "Joey", "Geraint"]
# After testing, I removed Ivy from this list. It sounded too child-like.
if atc_aws_voicemodel == "neural":
atc_voices = ["Olivia", "Amy", "Emma", "Brian", "Arthur", "Kajal", "Niamh", "Aria", "Ayanda", "Danielle", "Gregory", "Ivy", "Joanna", "Kendra", "Kimberly", "Salli", "Joey", "Matthew", "Ruth", "Stephen"]
# Missing in this list are Justin and Kevin -
# they are declared as being young child voices - you normally do not hear children on an ATC transmission.
# Setup our Polly session to AWS
atc_polly_client = boto3.Session(
aws_access_key_id=atc_aws_key,
aws_secret_access_key=atc_aws_secret,
region_name=atc_aws_region).client('polly')
# Last read line
atc_last_line = -1
# Init pygame and its mixer
pygame.init()
pygame.mixer.init()
# The click at the end of a transmission
click = pygame.mixer.Sound("endclick.wav")
# Open file before main loop
atc_log = open(atc_pilot2atc_log)
# Main run loop
while True:
atc_lines = atc_log.readlines()
idx = 0
for line in atc_lines:
if " ATC: " in line:
line = line.replace(" ATC: ", "")
if idx > atc_last_line:
# Update last read line
atc_last_line = idx
# Pick a voice
voice_to_use = random.randrange(len(atc_voices))
# Show what has been said so that it can be verified outside of Pilot2ATC - if the user wants it
if atc_show_responses == True:
print(" > ATC - [" + atc_voices[voice_to_use] + "]: " + line)
# Generate voice!
# Let's keep it at OGG - best compromize between data transfer size and quality
# Also, added 8Khz as sample frequency to make this sound more authentic
response = atc_polly_client.synthesize_speech(VoiceId=atc_voices[voice_to_use], OutputFormat='ogg_vorbis', Text = line, Engine = atc_aws_voicemodel, SampleRate="8000")
# And place that into a binary block
data = io.BytesIO(response['AudioStream'].read())
with open("atc.ogg", 'wb') as f:
f.write(data.getbuffer())
# Get length of spoken audio.
t = pygame.mixer.Sound("atc.ogg")
l = int(t.get_length()) + 1
# OK. Generate white noise:
noise = np.random.normal(0, 1, 8000 * l)
# Normalize the white noise
noise = noise / np.max(np.abs(noise))
# Convert the white noise to a 16-bit format
noise = (noise * 2**15).astype(np.int16)
# Save that file too
write('noise.wav', 8000, noise)
# Place Polly's audio in Channel 0
#pygame.mixer.music.load(data)
#pygame.mixer.music.play()
pygame.mixer.Channel(0).play(t)
# Set white noise volume to 10%
pygame.mixer.Channel(1).set_volume(0.05)
# Place white noise in Channel 1
pygame.mixer.Channel(1).play(pygame.mixer.Sound('noise.wav'))
while pygame.mixer.Channel(0).get_busy():
time.sleep(0.1)
pygame.mixer.Channel(2).set_volume(0.3)
pygame.mixer.Channel(2).play(click)
# Increase loop count
idx = idx + 1
atc_log.seek(0)
time.sleep(3)