import boto3 # pip install boto3 import pygame # pip install pygame 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 = "SERVER 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 X-Plane log file is located # This usually sits in the root of your X-Plane folder, named Log.txt # ------------------------------------------------------------------- atc_xplane_log = "M:\\Flight Sim\\Simulator\\12\\Log_tmp.txt" #atc_xplane_log = "C:\\Users\\windo\\Desktop\\Log.txt" # ------------------------------------------------------------------- # Put in your call sign. Must be the same you entered in 124th ATC # ------------------------------------------------------------------- atc_callsign = "MST" atc_flightno = "6012" # ------------------------------------------------------------------- # Do you want to hear "your voice" when contacting ATC? # ------------------------------------------------------------------- atc_captain_voice = True # ------------------------------------------------------------------- # Select your pilot's voice # Ideally you will need to remove your selected voice from the array # of available Polly voices below, so that it does not come up as # your ATC voice # ------------------------------------------------------------------- atc_pilot_voice = 12 # ------------------------------------------------------------------- # NO TRESPASSING BEYOND THIS POINT # ------------------------------------------------------------------- os.system("cls") print(" ") print(" ---------------------------------------------- ") print(" 124thAWS") print(" Making 124thATC sound more natural") print(" ---------------------------------------------- ") print(" Developed by MarStrMind") print(" License: MIT") print(" ---------------------------------------------- ") print(" Using file: " + atc_xplane_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() # Open file before main loop atc_log = open(atc_xplane_log) # Who spoke last - pilot or ATC atc_wsl = 1 # 1: pilot, 2: ATC. Initially set to 1 # Main run loop while True: atc_lines = atc_log.readlines() idx = 0 for line in atc_lines: if "Communication:" in line: content = line.split() c_idx = 0 for word in content: if word == "Communication:": break c_idx = c_idx + 1 new_l_el = 0 newline = "" for word in content: if new_l_el >= c_idx+1: newline = newline + " " + word new_l_el = new_l_el + 1 if idx > atc_last_line: # Update last read line atc_last_line = idx # Pick a voice - depending on current situation resp = "" voice_to_use = -1 content[c_idx+2] = content[c_idx+2].replace(",", "") if content[c_idx+1] == atc_callsign and content[c_idx+2] == atc_flightno: vc = random.randrange(len(atc_voices)) if vc == atc_pilot_voice: vc = vc-1 if vc == -1: vc = 1 voice_to_use = vc resp = "ATC" atc_wsl = 2 else: voice_to_use = atc_pilot_voice resp = "Pilot" atc_wsl = 1 # 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(" > " + resp + " - [" + atc_voices[voice_to_use] + "]: " + newline) # Let's replace the actual numbers with written, phonetic numbers to avoid things like # "6012" audible as "six thousand twelve". Note the space after each number. # We need to do this after the string checks performed before. # Placing this here shows original text in console - but pronounces the numbers correctly. newline = newline.replace("0", "Zero ") newline = newline.replace("1", "One ") newline = newline.replace("2", "Two ") newline = newline.replace("3", "Three ") newline = newline.replace("4", "Four ") newline = newline.replace("5", "Five ") newline = newline.replace("6", "Six ") newline = newline.replace("7", "Seven ") newline = newline.replace("8", "Eight ") newline = newline.replace("9", "Niner ") # Generate voice! # Let's keep it at OGG - best compromize between data transfer size and quality response = atc_polly_client.synthesize_speech(VoiceId=atc_voices[voice_to_use], OutputFormat='ogg_vorbis', Text = newline, Engine = atc_aws_voicemodel) # And place that into a binary block data = io.BytesIO(response['AudioStream'].read()) # Place the data into pygame and play it pygame.mixer.music.load(data) if resp == "ATC": pygame.mixer.music.play() if resp == "Pilot" and atc_captain_voice == True: pygame.mixer.music.play() pygame.event.wait() # Increase loop count idx = idx + 1 atc_log.seek(0) time.sleep(3)