Source code for audiomate.corpus.io.tuda

import collections
import os
import glob
import re

import audiomate
from audiomate import annotations
from audiomate import issuers
from audiomate.corpus.subset import subview
from . import base

SPEAKER_IDX_PATTERN = re.compile(r'<speaker_id>(.*?)</speaker_id>')
GENDER_PATTERN = re.compile(r'<gender>(.*?)</gender>')
TRANSCRIPTION_PATTERN = re.compile(r'<cleaned_sentence>(.*?)</cleaned_sentence>')
RAW_TRANSCRIPTION_PATTERN = re.compile(r'<sentence>(.*?)</sentence>')
AGE_PATTERN = re.compile(r'<ageclass>(.*?)</ageclass>')
NATIVE_PATTERN = re.compile(r'<muttersprachler>(.*?)</muttersprachler>')

SUBSETS = ['train', 'dev', 'test']

WAV_FILE_SUFFIXES = [
    'Kinect-Beam',
    'Kinect-RAW',
    'Realtek',
    'Samson',
    'Yamaha',
    'Microsoft-Kinect-Raw'
]

# Wrong transcripts, empty or to short
BAD_FILES = {
    'train': [
        # INVALID AUDIO
        '2014-03-18-15-29-23', '2014-03-18-15-28-52', '2014-03-24-13-39-24',
        '2014-08-05-11-08-34', '2014-03-27-11-50-33', '2014-03-21-11-40-39',

        # TO SHORT FOR THE TRANSCRIPTION
        '2014-08-04-13-09-09', '2014-08-04-13-14-27', '2014-08-04-13-39-33',
        '2014-03-20-10-44-06', '2014-08-04-13-39-55', '2014-08-04-13-23-36',
        '2014-08-04-13-13-57', '2014-08-04-13-15-41', '2014-08-04-13-39-11',
        '2014-08-04-13-05-54', '2014-08-04-13-05-57', '2014-05-13-11-42-53',
        '2014-08-04-13-07-47', '2014-08-04-13-08-49', '2014-08-04-13-11-42',
        '2014-08-04-13-08-28', '2014-08-04-13-11-36', '2014-08-04-13-16-45',
        '2014-03-17-13-06-10', '2014-08-04-13-14-38', '2014-03-17-13-07-50',
        '2014-08-27-11-05-29', '2014-08-04-13-06-26', '2014-08-04-13-07-42',
        '2014-08-04-13-08-45', '2014-03-27-10-47-21', '2014-06-17-13-46-27',
        '2014-03-17-13-16-59', '2014-03-17-13-09-27', '2014-08-04-13-37-33',
        '2014-08-04-13-15-34', '2014-08-04-13-15-45', '2014-08-04-13-06-01',
        '2014-08-04-13-04-58', '2014-08-04-13-16-29', '2014-08-04-13-08-53',
        '2014-08-04-13-21-42', '2014-08-04-13-40-11', '2014-08-04-13-15-20',
        '2014-03-17-13-03-26', '2014-08-04-13-21-50', '2014-08-04-13-05-35',
        '2014-08-04-13-22-57', '2014-08-04-13-22-17', '2014-08-04-13-39-21',
        '2014-08-04-13-21-58', '2014-08-04-13-23-01', '2014-08-04-13-15-29',
        '2014-08-04-13-37-12', '2014-08-04-13-37-54', '2014-08-04-13-14-04',
        '2014-08-04-13-14-57', '2014-08-04-13-11-13', '2014-08-04-13-08-01',
        '2014-03-17-13-11-22', '2014-08-04-13-37-57', '2014-08-04-13-22-34',
        '2014-03-17-13-18-30', '2014-08-04-13-04-41', '2014-03-19-14-33-45',
        '2014-08-04-13-08-56', '2014-08-04-13-05-10', '2014-08-04-13-06-53',
        '2014-08-04-13-08-17', '2014-08-04-13-14-08', '2014-05-06-12-17-19',
        '2014-08-04-13-41-10', '2014-08-04-13-22-41', '2014-08-04-13-37-29',
        '2014-08-04-13-16-58', '2014-03-17-13-20-25', '2014-08-04-13-05-06',
        '2014-08-04-13-08-10', '2014-03-17-13-05-15', '2014-08-04-13-11-31',
        '2014-08-04-13-11-53', '2014-08-04-13-13-04', '2014-03-20-10-53-52',
        '2014-08-04-13-21-34', '2014-08-04-13-05-49', '2014-08-04-13-05-22',
        '2014-08-04-13-39-00', '2014-08-04-13-05-45', '2014-03-17-13-06-05',
        '2014-08-04-13-05-42', '2014-08-04-13-15-38', '2014-08-04-13-39-42',
        '2014-06-17-13-46-39', '2014-08-04-13-22-49', '2014-08-04-13-22-02',
        '2014-08-04-13-23-22', '2014-08-04-13-05-19', '2014-08-04-13-09-04',
        '2014-08-04-13-37-16', '2014-08-04-13-39-03', '2014-08-04-13-22-05',
        '2014-08-04-13-11-18', '2014-08-04-13-09-22', '2014-08-04-13-38-56',
        '2014-08-04-13-16-37', '2014-08-04-13-07-54', '2014-08-04-13-37-19',
        '2014-08-04-13-22-53', '2014-05-13-12-01-27', '2014-08-04-13-15-07',
        '2014-08-04-13-22-37', '2014-08-04-13-39-59', '2014-08-04-13-39-50',
        '2014-08-04-13-21-54', '2014-08-04-13-11-01', '2014-08-04-13-23-09',
        '2014-08-04-13-37-41', '2014-08-04-13-13-30', '2014-08-04-13-05-02',
        '2014-08-04-13-14-30', '2014-08-04-13-39-29', '2014-08-04-13-37-45',
        '2014-03-17-13-17-22', '2014-08-04-13-40-04', '2014-03-17-13-03-57',
        '2014-08-04-13-09-27', '2014-08-04-13-06-21', '2014-08-04-13-41-03',
        '2014-08-04-13-06-49', '2014-08-04-13-16-20', '2014-08-04-13-37-22',
        '2014-08-04-13-21-29', '2014-08-04-13-06-31', '2014-08-04-13-16-02',
        '2014-08-04-13-09-13', '2014-03-17-13-14-56', '2014-08-04-13-08-05',
        '2014-05-06-10-50-37', '2014-08-04-13-14-12', '2014-08-04-13-15-02',
        '2014-08-04-13-13-49', '2014-08-04-13-40-07', '2014-08-04-13-23-13',
        '2014-08-04-13-14-53', '2014-08-04-13-08-40', '2014-03-17-13-18-33',
        '2014-08-04-13-39-16', '2014-08-04-13-23-05', '2014-08-04-13-05-26',
        '2014-08-04-13-05-30', '2014-08-04-13-06-12', '2014-08-04-13-05-14',
        '2014-08-04-13-41-18', '2014-03-17-13-15-57', '2014-08-04-13-04-37',
        '2014-08-04-13-14-00', '2014-08-04-13-15-11', '2014-03-17-13-15-42',
        '2014-08-04-13-41-22', '2014-03-17-13-04-03', '2014-08-04-13-11-56',
        '2014-08-04-13-37-49', '2014-08-04-13-14-35', '2014-08-04-13-07-58',
        '2014-08-04-13-06-09', '2014-08-04-13-10-53', '2014-08-04-13-41-14',
        '2014-08-04-13-37-36', '2014-08-04-13-10-57', '2014-08-04-13-13-33',
        '2014-03-17-13-19-59', '2014-08-04-13-13-22', '2014-08-04-13-04-49',
        '2014-08-04-13-13-37', '2014-08-04-13-23-17', '2014-08-04-13-11-40',
        '2014-08-04-13-14-42', '2014-08-04-13-09-00', '2014-08-04-13-13-53',
        '2014-08-04-13-15-49', '2014-03-17-13-13-51', '2014-08-04-13-17-01'
    ],
    'dev': [
        # INVALID AUDIO
        '2015-02-09-13-48-26', '2015-02-09-12-36-46', '2015-01-28-11-49-53',
        '2015-02-04-12-29-49'
    ],
    'test': [
        # INVALID AUDIO
        '2015-02-04-12-36-32', '2015-02-10-13-45-07', '2015-01-27-14-37-33',
        '2015-02-10-14-18-26'
    ]
}


[docs]class TudaReader(base.CorpusReader): """ Reader for the TUDA german distant speech corpus (german-speechdata-package-v2.tar.gz). Note: It only loads files ending in -beamformedSignal.wav .. seealso:: `<https://www.inf.uni-hamburg.de/en/inst/ab/lt/resources/data/acoustic-models.html>`_ Download page """
[docs] @classmethod def type(cls): return 'tuda'
def _check_for_missing_files(self, path): return [] def _load(self, path): corpus = audiomate.Corpus(path=path) for part in SUBSETS: sub_path = os.path.join(path, part) ids = TudaReader.get_ids_from_folder(sub_path, part) utt_ids = [] for idx in ids: add_ids = TudaReader.load_file(sub_path, idx, corpus) utt_ids.extend(add_ids) subview_filter = subview.MatchingUtteranceIdxFilter(utterance_idxs=utt_ids) subview_corpus = subview.Subview(corpus, filter_criteria=[subview_filter]) corpus.import_subview(part, subview_corpus) TudaReader.create_wav_type_subviews(corpus, utt_ids, prefix='{}_'.format(part)) TudaReader.create_wav_type_subviews(corpus, corpus.utterances.keys()) return corpus @staticmethod def create_wav_type_subviews(corpus, utt_ids, prefix=''): splits = collections.defaultdict(list) for utt_id in utt_ids: wavtype = utt_id.split('_')[-1] splits[wavtype].append(utt_id) for sub_name, sub_utts in splits.items(): subview_filter = subview.MatchingUtteranceIdxFilter(utterance_idxs=sub_utts) subview_corpus = subview.Subview(corpus, filter_criteria=[subview_filter]) corpus.import_subview('{}{}'.format(prefix, sub_name), subview_corpus)
[docs] @staticmethod def get_ids_from_folder(path, part_name): """ Return all ids from the given folder, which have a corresponding beamformedSignal file. """ valid_ids = set({}) for xml_file in glob.glob(os.path.join(path, '*.xml')): idx = os.path.splitext(os.path.basename(xml_file))[0] if idx not in BAD_FILES[part_name]: valid_ids.add(idx) return valid_ids
[docs] @staticmethod def load_file(folder_path, idx, corpus): """ Load speaker, file, utterance, labels for the file with the given id. """ xml_path = os.path.join(folder_path, '{}.xml'.format(idx)) wav_paths = [] for wav_suffix in WAV_FILE_SUFFIXES: wav_path = os.path.join(folder_path, '{}_{}.wav'.format(idx, wav_suffix)) if os.path.isfile(wav_path): wav_paths.append(wav_path) if len(wav_paths) == 0: return [] with open(xml_path, 'r', encoding='utf-8') as f: text = f.read() transcription = TudaReader.extract_value(text, TRANSCRIPTION_PATTERN, 'transcription', xml_path) transcription_raw = TudaReader.extract_value(text, RAW_TRANSCRIPTION_PATTERN, 'raw_transcription', xml_path) gender = TudaReader.extract_value(text, GENDER_PATTERN, 'gender', xml_path) is_native = TudaReader.extract_value(text, NATIVE_PATTERN, 'native', xml_path) age_class = TudaReader.extract_value(text, AGE_PATTERN, 'age', xml_path) speaker_idx = TudaReader.extract_value(text, SPEAKER_IDX_PATTERN, 'speaker_idx', xml_path) if speaker_idx not in corpus.issuers.keys(): start_age_class = int(age_class.split('-')[0]) if start_age_class < 12: age_group = issuers.AgeGroup.CHILD elif start_age_class < 18: age_group = issuers.AgeGroup.YOUTH elif start_age_class < 65: age_group = issuers.AgeGroup.ADULT else: age_group = issuers.AgeGroup.SENIOR native_lang = None if is_native == 'Ja': native_lang = 'deu' issuer = issuers.Speaker(speaker_idx, gender=issuers.Gender(gender), age_group=age_group, native_language=native_lang) corpus.import_issuers(issuer) utt_ids = [] for wav_path in wav_paths: wav_name = os.path.split(wav_path)[1] wav_idx = os.path.splitext(wav_name)[0] corpus.new_file(wav_path, wav_idx) utt = corpus.new_utterance(wav_idx, wav_idx, speaker_idx) utt.set_label_list(annotations.LabelList.create_single( transcription, idx=audiomate.corpus.LL_WORD_TRANSCRIPT )) utt.set_label_list(annotations.LabelList.create_single( transcription_raw, idx=audiomate.corpus.LL_WORD_TRANSCRIPT_RAW )) utt_ids.append(wav_idx) return utt_ids
@staticmethod def extract_value(text, pattern, value, path): m = pattern.search(text) if m: return m.group(1) else: raise ValueError('Value {} not found in {}'.format(value, path))