import numpy as np from scipy.io import wavfile # import audiogen import random import sys import subprocess # to play the resulting wave file import datetime # EAS alerts are heavily dependent on timestamps so this makes it easy to send a thing now import argparse # EAS alerts are heavily dependent on timestamps so this makes it easy/fun to send a thing now sameCompatibleTimestamp = datetime.datetime.now().strftime("%j%H%M") # parse command-line arguments parser = argparse.ArgumentParser() parser.add_argument("--code", "-c", nargs='?', default="") parser.add_argument("--attention", "-as", nargs='?', default='0') parser.add_argument("--attentionlength", "-al", nargs='?', default=10) parser.add_argument("--playaudiolive", "-pal", nargs='?', default=-1) parser.add_argument("--org", "-o", nargs='?', default="WXR") parser.add_argument("--event", "-e", nargs='?', default="RWT") parser.add_argument("--location", "-lo", nargs='?', default=None) parser.add_argument("--location00", "-l00", nargs='?', default="000000") parser.add_argument("--location01", "-l01", nargs='?', default=None) parser.add_argument("--location02", "-l02", nargs='?', default=None) parser.add_argument("--location03", "-l03", nargs='?', default=None) parser.add_argument("--location04", "-l04", nargs='?', default=None) parser.add_argument("--location05", "-l05", nargs='?', default=None) parser.add_argument("--location06", "-l06", nargs='?', default=None) parser.add_argument("--location07", "-l07", nargs='?', default=None) parser.add_argument("--location08", "-l08", nargs='?', default=None) parser.add_argument("--location09", "-l09", nargs='?', default=None) parser.add_argument("--location10", "-l10", nargs='?', default=None) parser.add_argument("--location11", "-l11", nargs='?', default=None) parser.add_argument("--location12", "-l12", nargs='?', default=None) parser.add_argument("--location13", "-l13", nargs='?', default=None) parser.add_argument("--location14", "-l14", nargs='?', default=None) parser.add_argument("--location15", "-l15", nargs='?', default=None) parser.add_argument("--location16", "-l16", nargs='?', default=None) parser.add_argument("--location17", "-l17", nargs='?', default=None) parser.add_argument("--location18", "-l18", nargs='?', default=None) parser.add_argument("--location19", "-l19", nargs='?', default=None) parser.add_argument("--location20", "-l20", nargs='?', default=None) parser.add_argument("--location21", "-l21", nargs='?', default=None) parser.add_argument("--location22", "-l22", nargs='?', default=None) parser.add_argument("--location23", "-l23", nargs='?', default=None) parser.add_argument("--location24", "-l24", nargs='?', default=None) parser.add_argument("--location25", "-l25", nargs='?', default=None) parser.add_argument("--location26", "-l26", nargs='?', default=None) parser.add_argument("--location27", "-l27", nargs='?', default=None) parser.add_argument("--location28", "-l28", nargs='?', default=None) parser.add_argument("--location29", "-l29", nargs='?', default=None) parser.add_argument("--location30", "-l30", nargs='?', default=None) parser.add_argument("--time", "-t", nargs='?', default="0015") parser.add_argument("--issued", "-i", nargs='?', default=sameCompatibleTimestamp) parser.add_argument("--callsign", "-cs", nargs='?', default="KEAX/NWS") args = parser.parse_args() ######## CONFIG / constants ######## markBitFrequency = 2083 + (1/3) spaceBitFrequency = 1562.5 print (args) fs = 43750 # t = 1.0 / (520 + (5/6)) # f = 2083.33333 samples = np.zeros(0) def markBit(): global markBitFrequency # f = 2083.33333 f = markBitFrequency t = 1.0 / (520 + (5/6)) samples = np.arange(t * fs) / fs roffle = np.sin(2 * np.pi * f * samples) return roffle * 0.8 def spaceBit(): global spaceBitFrequency # f = 1562.5 f = spaceBitFrequency t = 1.0 / (520 + (5/6)) samples = np.arange(t * fs) / fs return np.sin(2 * np.pi * f * samples) signal = np.zeros(20000) def byte(the_byte): sys.stdout.write(the_byte) sys.stdout.write(" ") byte_data = np.zeros(0) for i in range(0, 8): if ord(the_byte) >> i & 1: sys.stdout.write("1") byte_data = np.append(byte_data, markBit()) else: sys.stdout.write("0") byte_data = np.append(byte_data, spaceBit()) sys.stdout.write("\n") sys.stdout.flush() return byte_data def extramarks(numberOfMarks): """SAGE encoders seem to add a few mark bits at the beginning and end""" byte_data = np.zeros(0) for i in range(0, numberOfMarks): byte_data = np.append(byte_data, markBit()) return byte_data def preamble(): byte_data = np.zeros(0) for i in range(0, 16): byte_data = np.append(byte_data, markBit()) byte_data = np.append(byte_data, markBit()) byte_data = np.append(byte_data, spaceBit()) byte_data = np.append(byte_data, markBit()) byte_data = np.append(byte_data, spaceBit()) byte_data = np.append(byte_data, markBit()) byte_data = np.append(byte_data, spaceBit()) byte_data = np.append(byte_data, markBit()) return byte_data # SingleTone = # CombinedTone = LocationList = "" # arguments are location.00 to location.30 if args.location != None: LocationList = "-" + args.location else: Where = (args.location00, args.location01, args.location02, args.location03, args.location04, args.location05, args.location06, args.location07, args.location08, args.location09, args.location10,args.location11,args.location12, args.location13, args.location14, args.location15, args.location16, args.location17, args.location18, args.location19, args.location20, args.location21, args.location22, args.location23, args.location24, args.location25, args.location26, args.location27, args.location28, args.location29, args.location30) # LocationList = "-".join(Where) for i in range(0, 30): if Where[i] != None: LocationList+= "-" + Where[i] else: LocationList+= "" if LocationList == "": LocationList = "000000" print(LocationList) code = "ZCZC" + "-" + args.org + "-" + args.event + "" + LocationList + "+" + args.time + "-" + args.issued + "-" + args.callsign + "-" if args.code != "" and args.code != None and args.code != " ": code = args.code for i in range(0, 3): # signal = np.append(signal, extramarks(10)) signal = np.append(signal, preamble()) # turn each character into a sequence of sine waves for char in code: signal = np.append(signal, byte(char)) signal = np.append(signal, np.zeros(43750)) # wait the requisite one second # signal = np.append(signal, extramarks(6)) # ENDEC might not be as picky about this as I once thought sampleRate = 43750 length = np.linspace(0, args.attentionlength, sampleRate * args.attentionlength) tonesamples = length # (np.arange(length * sampleRate)/sampleRate) SingleTone = 1050 CombinedTone = [853, 960] attn = np.zeros(20000) tones = np.zeros(43750*8) if args.attention != 0: if args.attention == '1': tones = np.sin(2 * np.pi * SingleTone * tonesamples) elif args.attention == '2': tones = np.sin(2 * np.pi * CombinedTone[0] * tonesamples) + np.sin(2 * np.pi * CombinedTone[1] * tonesamples) attn = np.append(attn, tones*0.8) eom = np.zeros(20000) # EOM (3x) for i in range(0, 3): # signal = np.append(signal, extramarks(10)) eom = np.append(eom, preamble()) for char in "ZCZCNNNN": # NNNN = End Of Message eom = np.append(eom, byte(char)) # signal = np.append(signal, extramarks(6)) eom = np.append(eom, np.zeros(43750)) # wait the requisite one second signal *= 32767 signal = np.int16(signal) wavfile.write(str("same.wav"), fs, signal) if args.attention != 0: wavfile.write(str("attention.wav"), sampleRate, attn) wavfile.write(str("eom.wav"), fs, eom) if args.playaudiolive == "1": subprocess.call("afplay same.wav", shell=True) if args.attention != 0: subprocess.call("afplay attention.wav", shell=True) subprocess.call("afplay eom.wav", shell=True)