Как и многие, мне нравится слушать хороший подкаст. Один из тех, кого я наслаждался за эти годы Долина Лексики , подкаст о языке, который исследует так, как мы говорим, читать и писать. В недавнем эпизоде под названием «Это менестрельный стереотип, верно?» Хозяин исследовал использование «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”