Рубрики
Без рубрики

Обработка коллекций архивальных аудиозаписей

Этот проект смотрит на то, как автоматизировать анализ коллекции аудио, чтобы удалить шум из архивальных кадров. Помечено аудио, видео, Python.

Как и многие, мне нравится слушать хороший подкаст. Один из тех, кого я наслаждался за эти годы Долина Лексики , подкаст о языке, который исследует так, как мы говорим, читать и писать. В недавнем эпизоде под названием «Это менестрельный стереотип, верно?» Хозяин исследовал использование «AM» на черном американском английском языке.

Одна из этих записей проводится в 1940 году, а экс-раб назван Ирэном … говорить о том, как дела.

Интервью с Ириновым Уильямсом из Рима Миссисипи был захвачен без современных преимуществ профессиональных классов микрофонов или среды студии. Он говорит с общей задачей обработки средств массовой информации посмотреть на аудио, которые, возможно, были созданы в неоптимальных обстоятельствах, которые пытаются быть возмещены в создании нового носителя. Он также идентифицирует другую проблему того, как выполнять такие задачи в масштабе при работе с большими коллекциями СМИ.

Давайте посмотрим на некоторые трюки для автоматизации этого типа рабочего процесса с помощью Python и API для обработки носителя Dolby.io.

звуковая запись Приведены в подкасте и другие, как будто это часть коллекций, поддерживаемых Библиотека Конгресса Отказ

Мы можем использовать API для обработки носителей, чтобы получить небольшое представление о коллекции. Каждая запись в коллекции идентифицируется с уникальным идентификатором. Например, собеседование 3 части соответствует этим записям:

Было еще 60+ записей, и у каждого есть соответствующие аудиофайлы, которые можно загрузить. Как правило, Dolby.io Media Processing API, лучше всего работает с несжатыми исходными звуковыми файлами, так что я начал смотреть на некоторых из файлов .wav.

URL следует за шаблоном, который выглядит так: https://tile.loc.gov/storage-services/master/afc/afc1940003/AFC1940003_AFS04016/AFC1940003_AFS04016A.WAV.

Создание списка обработки

При работе с партией носителя можно помочь сделать список входных файлов, но и поддерживать состояние для обработки заданий и соответствующих выходных файлов. Мы можем сделать это с Python и файлом данных.

Например, мы могли бы начать с списка идентификаторов записи:

afc1984011_afs25745a
afc1941016_afs05500a
afc1984011_afs25745b
afc1941002_afs04778a
afc1984011_afs25750b
afc1941002_afs04777a
afc1984011_afs25659a
...

Мы можем переоценить список, чтобы сделать запрос на API в соответствии с API для получения некоторых основных данных о носителях.

def start_batch_processing():
    jobs = {}
    with open ('batch.txt', 'r') as batch:
        for line in batch.readlines():
            name = line.strip()
            if name.startswith('#'):
                continue
            (group_id, item_id) = name.split('_')
            dir_name = name.rstrip('ab')
            url = 'https://tile.loc.gov/storage-services/master/afc/{}/{}/{}.wav'.format(group_id, dir_name, name)

            jobs[name] = {
                'url': url,
                'job_id': None,
                'status': "Pending",
                'response': None,
            }

    for name in jobs.keys():
        print("Start Analyzing: {}".format(jobs[name]['url']))
        job_id = post_media_analyze(jobs[name]['url'])
        print(job_id)
        jobs[name]['job_id'] = job_id

    return jobs

Начать анализ

Для функций post_media_analyze () и get_media_analyze () Вы можете найти пример код в Dolbyio/Media-API-образцы Репозиторий на GitHub с помощью Запросы библиотека. Есть также некоторые образцы на других языках тоже.

СМИ материал дан как вход Параметр, который может быть любым любым мировым читаемым URL, таким как тот, который мы построили здесь из этой коллекции.

def get_url():
    return 'https://api.dolby.com/media/analyze'

def get_headers():
    return {
        "x-api-key": os.environ['DOLBYIO_API_KEY'],
        "Content-Type": "application/json",
        "Accept": "application/json",
    }

def post_media_analyze(input_url):
    url = get_url()
    headers = get_headers()
    body = {"input": input_url}

    response = requests.post(url, json=body, headers=headers)
    response.raise_for_status()
    return response.json()["job_id"]

def get_media_analyze(job_id):
    url = get_url()
    headers = get_headers()
    params = {"job_id": job_id}

    response = requests.get(url, params=params, headers=headers)
    response.raise_for_status()
    data = response.json()
    return data

Трек прогресс

Есть много способов поддерживать государство, но вообще это хорошая идея, чтобы отслеживать ваши job_id. и Статус в любых заданиях инициированных. Таким образом, если ваш рабочий процесс медиапровода прерывается или вы хотите возобновить или повторить существующую работу, у вас будет запись о том, какие работы работали и позже, где вы помещаете выходные файлы. Для простоты это может даже быть только данные JSON, это написано и прочитано из файла на диске.

def write_jobs(jobs, job_file):
    with open(job_file, 'w') as output:
        output.write(json.dumps(jobs, sort_keys=True, indent=4))

def read_jobs(job_file):
    with open(job_file, 'r') as json_jobs:
        jobs = json.load(json_jobs)
        return jobs

Мы можем использовать этот файл между ITERATIONS и LOOP, чтобы убедиться, что все задания достигают полного состояния (I.E. Успех или неудачно).

def check_job_status(jobs):
    # Check status until all jobs are complete
    active_jobs = True
    while active_jobs:
        active_jobs = False
        for name in jobs.keys():
            # Pending and Running status indicate the job is still processing
            status = jobs[name]['status']
            if status in {"Pending", "Running"}:
                # Check again to see if there has been a change since
                # the last loop.
                response = get_media_analyze(jobs[name]['job_id'])
                jobs[name]['status'] = response['status']
                if response['status'] in {"Pending", "Running"}:
                    active_jobs = True
                else:
                    # The job is complete, also store the response for later
                    logging.debug(response['status'])
                    jobs[name]['response'] = response

        # Wait a bit and then retry
        time.sleep(5)

    return jobs

После обработки завершится для всех заданий, у меня есть сбор данных об этих файлах, которые могут предоставить некоторые интересные идеи.

Чтобы узнать немного больше о коллекции, мы можем собрать данные в рамку данных Pandas. Если вы не знакомы с этим, Пандас Является ли библиотека анализа данных Python, которая может быть очень удобной для изучения данных. Также может быть полезно использовать интерактивный инструмент, такой как iPython REPL или ноутбук Jupyter во время этой ситуации Explore.

import pandas

def get_dataframe(jobs):
    df = pandas.DataFrame()
    for item in jobs:
        result = jobs[item]['response']['result']
        row = pandas.json_normalize(result, sep='.')
        row['label'] = item
        df.append(row)

    return df

df = get_dataframe(jobs)
print(df.columns)

То, что мы здесь сделали, – это сглаживание ключей от ответа JSON, возвращаемой из обработки медиа, анализирующих API, чтобы он был доступен в табличном формате, который мы можем запросить и сделать некоторые данные анализа данных.

Index(['media_info.container.kind', 'media_info.container.duration',
       'media_info.container.bitrate', 'media_info.container.size',
       'media_info.audio.codec', 'media_info.audio.bit_depth',
       'media_info.audio.channels', 'media_info.audio.sample_rate',
       'media_info.audio.duration', 'media_info.audio.bitrate',
       'audio.clipping.num_sections', 'audio.loudness.measured',
       'audio.loudness.range', 'audio.loudness.gating_mode',
       'audio.loudness.sample_peak', 'audio.loudness.true_peak',
       'audio.bandwidth', 'audio.noise.snr_average',
       'audio.noise.level_average', 'audio.music.percentage',
       'audio.music.num_sections', 'audio.other.percentage',
       'audio.other.num_sections', 'audio.speech.percentage',
       'audio.speech.num_sections', 'audio.silence.percentage',
       'audio.silence.num_sections'],
      dtype='object')

Общая продолжительность

В качестве примера нам может быть любопытно, сколько анализует коллекцию, как это будет стоить. Используя Цены Страница мы можем придумать оценку, основанную на общей проанализированной средств массовой информации.

# Sum the file duration (in seconds) and then calculate cost
total_cost = df['media_info.audio.duration'].sum() / 60 * .05

Оказывается, коллекция имеет над 450 минут содержания, которое займет много времени, если бы нам пришлось слушать и повторно слушать эти файлы вручную в цифровой аудио рабочей станции.

Обнаружение аудио аномалий

Мы могли бы заинтересовать в выявлении аномалий. Через целую коллекцию мы можем ожидать некоторую однородность, когда речь идет о настройках кодирования, поэтому любые выбросы станут интересными.

Мы могли бы посмотреть на битрейт:

> df['media_info.container.bitrate'].value_counts()
1411200    50
705600      8
1411199     4

Или мы могли бы проверить количество каналов:

> df['media_info.audio.channels'].value_counts()
2    54
1     8

Мы можем повторить этот шаблон для кодека, образец_rate и т. Д.

Обнаружение проблем

При рассмотрении громкости или шума значения менее дискретной, поэтому мы можем искать средства Media, которые превышают пороговые значения, которые имеют значение для нашего применения.

Например, давайте посмотрим на шум.

> df['audio.noise.level_average'].describe()
count    62.000000
mean    -65.693226
std      13.105599
min     -89.320000
25%     -75.380000
50%     -62.640000
75%     -53.910000
max     -47.740000

Чтобы посмотреть только на файлы с наибольшим количеством шума, мы можем группировать эти непрерывные значения в дискретные ведра или мусорные баки. Например:

> df['noise.bins'] = pandas.cut(df['audio.noise.level_average'], [-90, -80, -70, -60, -50, -40])
> df['noise.bins'].value_counts()
(-90, -80]    12
(-80, -70]    14
(-70, -60]     7
(-60, -50]    24
(-50, -40]     5

Учитывая, что это архивные кадры, это не неожиданно находить много шума в записях, но это может помочь нам приоритетировать, какие СМИ выходят за рамки восстановления или где вкладывать фокус на ручные рабочие процессы.

Посмотрев на эти идеи о коллекции в целом, мы можем захотеть выбрать несколько файлов для улучшения качества. Мы можем сделать это со средней носителями API.

Давайте используем тот же пакетный механизм, чтобы сосредоточиться на подмножестве файлов. Нам нужно немного изменить его, чтобы также объяснить, где отправлять расширенные результаты.

def get_url():
    return 'https://api.dolby.com/media/enhance'

def post_media_enhance(input_url, output_url):
    url = get_url()
    body = {"input": input_url, "output": output_url}
        body = {
        "input": input_url, 
        "output": output_url,
        "audio": {
            "speech": {
                "isolation": {
                    "amount": 100
                }
            }
        }
    }

    response = requests.post(url, json=body, headers=headers)
    response.raise_for_status()
    return response.json()["job_id"]

Есть несколько различий, чтобы заменить.

Во-первых, мы должны предоставить параметр API для того, чтобы откуда установить выход после обработки. Это может быть местоположение облачного хранения, которое я уже имел в наличии для использования для моих приложений, но требование является URL – это то, что Dolby.io API может сделать Поставить запрос. Вход в носитель и вывод Учебник входит в более подробную информацию о некоторых из этих вариантов.

Для этого проекта я использовал Dolby.io СМИ вывод API. Указав выходной URL, такой как dlb:///out/afc1940003_afs04011a.enhanced.wav. Файл доступен для загрузки и может быть коррелирован с входным файлом с одним и тем же элементом я бы.

Во-вторых, API API Media будет делать все возможное, чтобы улучшить содержание через интеллектуальный подход для управления шумом, балансируя шумоподавление и речевую изоляцию. С плохими поврежденными записями, подобными этим, токарная речь выделения до 100 дает лучшие результаты. Как только я определяю правильную настройку на несколько файлов образцов, то же самое можно применять ко всей коллекции, которая была создана с использованием аналогичных производственных подходов.

Как только работа выгнала, я монирую работу с коллекцией деталей в локальном файле на диске, как это:

{
    "afc1984011_afs25745a": {
        "job_id": "43dc001d-44ce-4694-b8d2-b72974f4ba81",
        "output_path": "afc1984011_afs25745a.enhanced.wav",
        "output_url": "dlb://out/afc1984011_afs25745a.enhanced.wav",
        "response": null,
        "status": "Pending",
        "url": "https://tile.loc.gov/storage-services/master/afc/afc1984011/afc1984011_afs25745/afc1984011_afs25745a.wav"
}

Загрузка вывода

Если вы использовали свое собственное хранилище, вы можете хранить его в ведре S3 или на другой сервис, готов к вашему обзору. Чтобы забрать обработанный результат из API Dolby.io Media API, мне нужно будет загрузить файл с конечной точки/мультимедиа/вывода.

def get_media_output(output_url, local_output_path):
    url = 'https://api.dolby.com/media/output'
    headers = get_headers()
    args = {
        "url": output_url
    }

    with requests.get(url, params=args, headers=headers, stream=True) as response:
        response.raise_for_status()
        response.raw.decode_content = True
        print("Downloading {0}".format(output_url))
        with open(local_output_path, "wb") as output_file:
            shutil.copyfileobj(response.raw, output_file)

...

for name in jobs.keys():
    ...
    if jobs[name]['status'] == "Success":
        get_media_output(jobs[name]['output_url'], jobs[name]['output_path'])

После этого Podcast Episode один из сообществ аудиожиготехнических сообщений взял на себя историю и обработал некоторые файлы из этой коллекции вручную. Дух сообщества для толпа-источника этих усилий возглавил еще несколько, чтобы перейти и попробовать различные инструменты для очистки звука.

Столкнувшись с большой коллекцией носителей, таких как с такой задачей, возможность воспользоваться преимуществами горизонтального масштабирования, предоставляемого от API, становится очень мощным. Вместо того, чтобы прослушать 450 минут аудио и редактирование его вручную, эластичность облака позволила мне обработать всю партию с очень хорошими результатами, при этом, позволяя алгоритмам сделать тяжелую работу.

Надеюсь, что некоторые из этих образцов Python помогут вам начать автоматизировать свои собственные рабочие процессы средств массовой информации для улучшения и получения понимания коллекций аудио.

использованная литература

Ломакс, Джон А и др. Интервью с Ирэн Уильямсом, Римом, Миссисипи, октября. Рим, Миссисипи, 1940. PDF. Извлечено из библиотеки конгресса.

Оригинал: “https://dev.to/dolbyio/processing-collections-of-archival-audio-recordings-5gi3”