Allow loading if multiple languages and selection both via

default in config file and OPTIONS.

Remove ANNOUNCEMENT_LANGUAGE from [GLOBAL]
Replace with ANNOUNCEMENT_LANGUAGES - Comma Separated list

Current list:

ANNOUNCEMENT_LANGUAGES: en_GB,en_GB_2,en_US,es_ES,es_ES_2,fr_FR,de_DE,dk_DK,it_IT,no_NO,pl_PL,se_SE

Add:

ANNOUNCEMENT_LANGUAGE to MASTER definition. If using GENERATOR, this becomes
the template default.

To change via OPTIONS add LANG=<language code>

take codes from list above
This commit is contained in:
Simon 2021-05-14 00:07:11 +01:00
parent eb300e3de3
commit 25bd7db348
3 changed files with 172 additions and 146 deletions

View File

@ -496,24 +496,25 @@ def sendSpeech(self,speech):
def disconnectedVoice(system):
_nine = bytes_3(9)
_source_id = bytes_3(5000)
_lang = CONFIG['SYSTEMS'][system]['ANNOUNCEMENT_LANGUAGE']
logger.debug('(%s) Sending disconnected voice',system)
_say = [words['silence']]
_say.append(words['silence'])
_say = [words[_lang]['silence']]
_say.append(words[_lang]['silence'])
if CONFIG['SYSTEMS'][system]['DEFAULT_REFLECTOR'] > 0:
_say.append(words['silence'])
_say.append(words['linkedto'])
_say.append(words['silence'])
_say.append(words['to'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['linkedto'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['to'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
for number in str(CONFIG['SYSTEMS'][system]['DEFAULT_REFLECTOR']):
_say.append(words[number])
_say.append(words['silence'])
_say.append(words[_lang][number])
_say.append(words[_lang]['silence'])
else:
_say.append(words['notlinked'])
_say.append(words[_lang]['notlinked'])
_say.append(words['silence'])
_say.append(words[_lang]['silence'])
speech = pkt_gen(_source_id, _nine, bytes_4(9), 1, _say)
@ -545,6 +546,7 @@ def ident():
if CONFIG['SYSTEMS'][system]['MODE'] != 'MASTER':
continue
if CONFIG['SYSTEMS'][system]['VOICE_IDENT'] == True:
_lang = CONFIG['SYSTEMS'][system]['ANNOUNCEMENT_LANGUAGE']
if CONFIG['SYSTEMS'][system]['MAX_PEERS'] > 1:
logger.debug("(IDENT) %s System has MAX_PEERS > 1, skipping",system)
continue
@ -560,31 +562,31 @@ def ident():
if (_slot['RX_TYPE'] == HBPF_SLT_VTERM) and (_slot['TX_TYPE'] == HBPF_SLT_VTERM) and (time() - _slot['TX_TIME'] > CONFIG['SYSTEMS'][system]['GROUP_HANGTIME']):
#_stream_id = hex_str_4(1234567)
logger.info('(%s) System idle. Sending voice ident',system)
_say = [words['silence']]
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['this-is'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say = [words[_lang]['silence']]
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['this-is'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_systemcs = re.sub(r'\W+', '', _callsign)
_systemcs.upper()
for character in _systemcs:
_say.append(words[character])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words[_lang][character])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
_say.append(words['freedmr'])
_say.append(words[_lang]['freedmr'])
#test
#_say.append(AMBEobj.readSingleFile('alpha.ambe'))
@ -680,6 +682,10 @@ def options_config():
CONFIG['SYSTEMS'][_system]['VOICE_IDENT'] = bool(int(_options['VOICE']))
logger.debug("(OPTIONS) %s - Setting voice ident to %s",_system,CONFIG['SYSTEMS'][_system]['VOICE_IDENT'])
if 'LANG' in _options and _options['LANG'] in words and _options['LANG'] != CONFIG['SYSTEMS'][_system]['ANNOUNCEMENT_LANGUAGE'] :
CONFIG['SYSTEMS'][_system]['ANNOUNCEMENT_LANGUAGE'] = _options['LANG']
logger.debug("(OPTIONS) %s - Setting voice language to %s",_system,CONFIG['SYSTEMS'][_system]['ANNOUNCEMENT_LANGUAGE'])
if 'SINGLE' in _options and (CONFIG['SYSTEMS'][_system]['SINGLE_MODE'] != bool(int(_options['SINGLE']))):
CONFIG['SYSTEMS'][_system]['SINGLE_MODE'] = bool(int(_options['SINGLE']))
logger.debug("(OPTIONS) %s - Setting SINGLE_MODE to %s",_system,CONFIG['SYSTEMS'][_system]['SINGLE_MODE'])
@ -1643,6 +1649,8 @@ class routerHBP(HBSYSTEM):
_nine = bytes_3(9)
_lang = CONFIG['SYSTEMS'][self._system]['ANNOUNCEMENT_LANGUAGE']
_int_dst_id = int_id(_dst_id)
#Handle private calls (for reflectors)
@ -1711,7 +1719,7 @@ class routerHBP(HBSYSTEM):
if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM):
#Speak callsign before message
_say = [words['silence']]
_say = [words[_lang]['silence']]
# _systemcs = re.sub(r'\W+', '', self._system)
# _systemcs.upper()
# for character in _systemcs:
@ -1721,8 +1729,8 @@ class routerHBP(HBSYSTEM):
#If disconnection called
if _int_dst_id == 4000:
logger.info('(%s) Reflector: voice called - 4000 "not linked"', self._system)
_say.append(words['notlinked'])
_say.append(words['silence'])
_say.append(words[_lang]['notlinked'])
_say.append(words[_lang]['silence'])
#If status called
elif _int_dst_id == 5000:
@ -1735,35 +1743,35 @@ class routerHBP(HBSYSTEM):
if _system['SYSTEM'] == self._system and _slot == _system['TS']:
if _system['ACTIVE'] == True:
logger.info('(%s) Reflector: voice called - 5000 status - "linked to %s"', self._system,_dehash_bridge)
_say.append(words['silence'])
_say.append(words['linkedto'])
_say.append(words['silence'])
_say.append(words['to'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['linkedto'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['to'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
for num in str(_dehash_bridge):
_say.append(words[num])
_say.append(words[_lang][num])
_active = True
break
if _active == False:
logger.info('(%s) Reflector: voice called - 5000 status - "not linked"', self._system)
_say.append(words['notlinked'])
_say.append(words[_lang]['notlinked'])
#Speak what TG was requested to link
else:
logger.info('(%s) Reflector: voice called (linking) "linked to %s"', self._system,_int_dst_id)
_say.append(words['silence'])
_say.append(words['linkedto'])
_say.append(words['silence'])
_say.append(words['to'])
_say.append(words['silence'])
_say.append(words['silence'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['linkedto'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['to'])
_say.append(words[_lang]['silence'])
_say.append(words[_lang]['silence'])
for num in str(_int_dst_id):
_say.append(words[num])
_say.append(words[_lang][num])
speech = pkt_gen(bytes_3(5000), _nine, bytes_4(9), 1, _say)
@ -2104,7 +2112,7 @@ if __name__ == '__main__':
_systemname = system+'-'+str(count)
generator[_systemname] = copy.deepcopy(CONFIG['SYSTEMS'][system])
generator[_systemname]['PORT'] = generator[_systemname]['PORT'] + count
generator[_systemname]['_default_options'] = "TS1_STATIC={};TS2_STATIC={};SINGLE={};DEFAULT_UA_TIMER={};DEFAULT_REFLECTOR={};VOICE={}".format(generator[_systemname]['TS1_STATIC'],generator[_systemname]['TS2_STATIC'],int(generator[_systemname]['SINGLE_MODE']),generator[_systemname]['DEFAULT_UA_TIMER'],generator[_systemname]['DEFAULT_REFLECTOR'],int(generator[_systemname]['VOICE_IDENT']) )
generator[_systemname]['_default_options'] = "TS1_STATIC={};TS2_STATIC={};SINGLE={};DEFAULT_UA_TIMER={};DEFAULT_REFLECTOR={};VOICE={};LANG={}".format(generator[_systemname]['TS1_STATIC'],generator[_systemname]['TS2_STATIC'],int(generator[_systemname]['SINGLE_MODE']),generator[_systemname]['DEFAULT_UA_TIMER'],generator[_systemname]['DEFAULT_REFLECTOR'],int(generator[_systemname]['VOICE_IDENT']), generator[_systemname]['ANNOUNCEMENT_LANGUAGE'])
logger.debug('(GLOBAL) Generator - generated system %s',_systemname)
generator[_systemname]['_default_options']
systemdelete.append(system)
@ -2163,18 +2171,21 @@ if __name__ == '__main__':
logger.info('(REPORT) TCP Socket reporting not configured')
#Read AMBE
AMBEobj = readAMBE(CONFIG['GLOBAL']['ANNOUNCEMENT_LANGUAGE'],'./Audio/')
AMBEobj = readAMBE(CONFIG['GLOBAL']['ANNOUNCEMENT_LANGUAGES'],'./Audio/')
#global words
words = AMBEobj.readfiles()
logger.info('(AMBE) Read %s words into voice dict',len(words) - 1)
for lang in words.keys():
logger.info('(AMBE) for language %s, read %s words into voice dict',lang,len(words[lang]) - 1)
#Remap words for internationalisation
if CONFIG['GLOBAL']['ANNOUNCEMENT_LANGUAGE'] in voiceMap:
logger.info('(AMBE) i8n voice map entry for language %s',CONFIG['GLOBAL']['ANNOUNCEMENT_LANGUAGE'])
_map = voiceMap[CONFIG['GLOBAL']['ANNOUNCEMENT_LANGUAGE']]
for _mapword in _map:
logger.info('(AMBE) Mapping \"%s\" to \"%s\"',_mapword,_map[_mapword])
words[_mapword] = words[_map[_mapword]]
#Remap words for internationalisation
if lang in voiceMap:
logger.info('(AMBE) i8n voice map entry for language %s',lang)
_map = voiceMap[lang]
for _mapword in _map:
logger.info('(AMBE) Mapping \"%s\" to \"%s\"',_mapword,_map[_mapword])
words[lang][_mapword] = words[lang][_map[_mapword]]
# HBlink instance creation
logger.info('(GLOBAL) FreeDMR \'bridge_master.py\' -- SYSTEM STARTING...')
@ -2191,6 +2202,9 @@ if __name__ == '__main__':
if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE':
systems[system] = routerOBP(system, CONFIG, report_server)
else:
if CONFIG['SYSTEMS'][system]['ANNOUNCEMENT_LANGUAGE'] not in CONFIG['GLOBAL']['ANNOUNCEMENT_LANGUAGES'].split(','):
logger.warning('(GLOBAL) Invalid language in ANNOUNCEMENT_LANGUAGE, skipping system %s',system)
continue
systems[system] = routerHBP(system, CONFIG, report_server)
listeningPorts[system] = reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP'])
logger.debug('(GLOBAL) %s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system])

View File

@ -124,7 +124,7 @@ def build_config(_config_file):
'TG2_ACL': config.get(section, 'TGID_TS2_ACL'),
'GEN_STAT_BRIDGES': config.getboolean(section, 'GEN_STAT_BRIDGES'),
'ALLOW_NULL_PASSPHRASE': config.getboolean(section, 'ALLOW_NULL_PASSPHRASE'),
'ANNOUNCEMENT_LANGUAGE': config.get(section, 'ANNOUNCEMENT_LANGUAGE'),
'ANNOUNCEMENT_LANGUAGES': config.get(section, 'ANNOUNCEMENT_LANGUAGES'),
'SERVER_ID': config.get(section, 'SERVER_ID')
})
@ -284,7 +284,8 @@ def build_config(_config_file):
'TS1_STATIC': config.get(section,'TS1_STATIC'),
'TS2_STATIC': config.get(section,'TS2_STATIC'),
'DEFAULT_REFLECTOR': config.getint(section, 'DEFAULT_REFLECTOR'),
'GENERATOR': config.getint(section, 'GENERATOR')
'GENERATOR': config.getint(section, 'GENERATOR'),
'ANNOUNCEMENT_LANGUAGE': config.get(section, 'ANNOUNCEMENT_LANGUAGE')
}})
CONFIG['SYSTEMS'][section].update({'PEERS': {}})

View File

@ -6,10 +6,10 @@ import glob
class readAMBE:
def __init__(self, lang,path):
self.lang = lang
self.langcsv = lang
self.langs = lang.split(',')
self.path = path
self.prefix = path+lang
def _make_bursts(self,data):
it = iter(data)
for i in range(0, len(data), 108):
@ -17,91 +17,102 @@ class readAMBE:
#Read indexed files
def readfiles(self):
_AMBE_LENGTH = 9
indexDict = {}
if os.path.isdir(self.prefix):
ambeBytearray = {}
_wordBitarray = bitarray(endian='big')
_wordBADict = {}
_glob = self.prefix + "/*.ambe"
for ambe in glob.glob(_glob):
basename = os.path.basename(ambe)
_voice,ext = basename.split('.')
inambe = open(ambe,'rb')
_wordBitarray.frombytes(inambe.read())
inambe.close()
_wordBADict[_voice] = []
pairs = 1
_lastburst = ''
for _burst in self._make_bursts(_wordBitarray):
#Not sure if we need to pad or not? Seems to make little difference.
if len(_burst) < 108:
pad = (108 - len(_burst))
for i in range(0,pad,1):
_burst.append(False)
if pairs == 2:
_wordBADict[_voice].append([_lastburst,_burst])
_lastburst = ''
pairs = 1
next
else:
pairs = pairs + 1
_lastburst = _burst
_wordBitarray.clear()
_wordBADict['silence'] = ([
[bitarray('101011000000101010100000010000000000001000000000000000000000010001000000010000000000100000000000100000000000'),
bitarray('001010110000001010101000000100000000000010000000000000000000000100010000000100000000001000000000001000000000')]
])
return _wordBADict
else:
try:
with open(self.prefix+'.indx') as index:
for line in index:
(voice,start,length) = line.split()
indexDict[voice] = [int(start) * _AMBE_LENGTH ,int(length) * _AMBE_LENGTH]
index.close()
except IOError:
return False
_AMBE_LENGTH = 9
_wordBADictofDicts = {}
ambeBytearray = {}
_wordBitarray = bitarray(endian='big')
for _lang in self.langs:
_prefix = self.path+_lang
_wordBADict = {}
try:
with open(self.prefix+'.ambe','rb') as ambe:
for _voice in indexDict:
ambe.seek(indexDict[_voice][0])
_wordBitarray.frombytes(ambe.read(indexDict[_voice][1]))
#108
_wordBADict[_voice] = []
pairs = 1
_lastburst = ''
for _burst in self._make_bursts(_wordBitarray):
indexDict = {}
if os.path.isdir(_prefix):
ambeBytearray = {}
_wordBitarray = bitarray(endian='big')
_wordBADict = {}
_glob = _prefix + "/*.ambe"
for ambe in glob.glob(_glob):
basename = os.path.basename(ambe)
_voice,ext = basename.split('.')
inambe = open(ambe,'rb')
_wordBitarray.frombytes(inambe.read())
inambe.close()
_wordBADict[_voice] = []
pairs = 1
_lastburst = ''
for _burst in self._make_bursts(_wordBitarray):
#Not sure if we need to pad or not? Seems to make little difference.
if len(_burst) < 108:
pad = (108 - len(_burst))
for i in range(0,pad,1):
_burst.append(False)
if pairs == 2:
_wordBADict[_voice].append([_lastburst,_burst])
_lastburst = ''
pairs = 1
next
else:
pairs = pairs + 1
_lastburst = _burst
_wordBitarray.clear()
ambe.close()
except IOError:
return False
_wordBADict['silence'] = ([
[bitarray('101011000000101010100000010000000000001000000000000000000000010001000000010000000000100000000000100000000000'),
bitarray('001010110000001010101000000100000000000010000000000000000000000100010000000100000000001000000000001000000000')]
])
return _wordBADict
if len(_burst) < 108:
pad = (108 - len(_burst))
for i in range(0,pad,1):
_burst.append(False)
if pairs == 2:
_wordBADict[_voice].append([_lastburst,_burst])
_lastburst = ''
pairs = 1
next
else:
pairs = pairs + 1
_lastburst = _burst
_wordBitarray.clear()
_wordBADict['silence'] = ([
[bitarray('101011000000101010100000010000000000001000000000000000000000010001000000010000000000100000000000100000000000'),
bitarray('001010110000001010101000000100000000000010000000000000000000000100010000000100000000001000000000001000000000')]
])
_wordBADictofDicts[_lang] = _wordBADict
else:
try:
with open(_prefix+'.indx') as index:
for line in index:
(voice,start,length) = line.split()
indexDict[voice] = [int(start) * _AMBE_LENGTH ,int(length) * _AMBE_LENGTH]
index.close()
except IOError:
return False
ambeBytearray = {}
_wordBitarray = bitarray(endian='big')
_wordBADict = {}
try:
with open(_prefix+'.ambe','rb') as ambe:
for _voice in indexDict:
ambe.seek(indexDict[_voice][0])
_wordBitarray.frombytes(ambe.read(indexDict[_voice][1]))
#108
_wordBADict[_voice] = []
pairs = 1
_lastburst = ''
for _burst in self._make_bursts(_wordBitarray):
#Not sure if we need to pad or not? Seems to make little difference.
if len(_burst) < 108:
pad = (108 - len(_burst))
for i in range(0,pad,1):
_burst.append(False)
if pairs == 2:
_wordBADict[_voice].append([_lastburst,_burst])
_lastburst = ''
pairs = 1
next
else:
pairs = pairs + 1
_lastburst = _burst
_wordBitarray.clear()
ambe.close()
except IOError:
return False
_wordBADict['silence'] = ([
[bitarray('101011000000101010100000010000000000001000000000000000000000010001000000010000000000100000000000100000000000'),
bitarray('001010110000001010101000000100000000000010000000000000000000000100010000000100000000001000000000001000000000')]
])
_wordBADictofDicts[_lang] = _wordBADict
return _wordBADictofDicts
#Read a single ambe file from the audio directory
def readSingleFile(self,filename):
ambeBytearray = {}