LINUX.ORG.RU

Чтение звукового файла с «правильной» скоростью

 


1

1

Добрый вечер.

Мне нужно сэмулировать в рамках одной программы весь аудиостек: считать звуковой файл (для определённости несжатый, т. е. WAV PCM или как оно там) и «воспроизвести» с корректной скоростью, т. е. 1 сэмпл в 1/F секунд, где F — частота дискретизации. Под воспроизведением понимается вызов некоторой функции на каждый сэмпл, т. е. это не воспроизведение через звуковую карту.

Если считать, что «воспроизведение» одного сэмпла уже написано, как реализовать считывание и нужные задержки между сэмплами? Временем обработки одного сэмпла, насколько понимаю, пренебречь нельзя, т. е. sleep(1/f) не сработает.

(На самом деле не воспроизвести, а моргать лампочками через USB-реле.)

★★★★★

Последнее исправление: intelfx (всего исправлений: 2)
Ответ на: комментарий от intelfx

Это как раз таки сложнее всего, т.к. требует специально подготовленных файлов + тебе придется жестко синхронизировать запуск файла, управляющего цветомузыкой, с самим музлом.

Погуглил бы в интернете схемы — есть совсем уж элементарные.

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

Ну или пиши демона. В alsa есть эмуляция oss, так что, маяться дурью с идиотскими API ALSA тебе не придется — используй простое чтение /dev/dsp, как в OSS.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от intelfx

Вопрос был в том, как посылать на выход ровно один фрейм в 1/44100 секунды (при F=44.1 kHz) без накапливающейся ошибки.

Да никак! Тебе нужен аппаратный буфер, в который ты будешь сливать данные по принципу «слил сколько слилось, и спать». Тебе уже предлагали заюзать FT232 в режиме BitBang. Как-то это должно делаться и на MK, и опять там есть как минимум один аппаратный буфер — UART — откуда обработчик прерывания читает пакет данных, преобразует его в набор управляющих воздействий, и отправляет МК спать ровно до следующего прерывания таймера.

Macil ★★★★★
()
Последнее исправление: Macil (всего исправлений: 1)
Ответ на: комментарий от Eddy_Em

ну, ты не перегибай.

зачем разбираться с форматом аудио, когда это уже реализовано? за то можно сфокусироваться на основной задаче.

aol ★★★★★
()
Ответ на: комментарий от aol

зачем разбираться с форматом аудио, когда это уже реализовано?

Формат wav — элементарщина. И ради него тащить какую-то левую библиотеку — бред!

Ты еще ffmpeg предложи использовать...

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

ты меня разочаровываешь.

если любой, даже самый сложный, проект разобрать на довольно подробные части, то каждая из этих частей будет, как ты говоришь, «элементарщиной». Но это же не повод каждую элементарщину писать с нуля!

И не пытайся тут развести флейм всякими лабвью и ффмпегами.

aol ★★★★★
()
Ответ на: комментарий от intelfx

timer_create и компания сработают?

Да. Делай

const int64_t interval = 1000*1000*1000 / 44100;
clock_gettime(CLOCK_MONOTONIC, &timing);
while (1) {
    timing.tv_nsec += interval;
    timing.tv_sec += timing.tv_nsec / (1000*1000*1000);
    timing.tv_nsec = timing.tv_nsec % (1000*1000*1000);
    clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &timing, NULL);
    do_work();
}

Ещё лучше использовать CLOCK_MONOTONIC_RAW, если есть.

Krieger_Od ★★
()
Ответ на: комментарий от Macil

Бегло прочтя даташит, я не нашёл, как там можно сделать пакетный битбанг на частоте в десятки килогерц. Сейчас погляжу пристальнее.

intelfx ★★★★★
() автор топика
Ответ на: комментарий от intelfx

молодец! :) просто в ОП этого нет, а всю портянку читать у меня пока нет времени.

aol ★★★★★
()
Ответ на: комментарий от aol

Ты несешь дикую пургу и сбиваешь ТСа с пути истинного! Ему нафиг не нужны эти звуковые файлы и wav. Ему тупо нужно слушать, что в текущий момент идет на колонки (ставим галочку "mix" в alsamixer и читаем с канала захвата) и выдавать команды на 232-й.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от intelfx

Тебе не нужны десятки килогерц для светомузыки! Или ты решил ШИМ эмулировать таким образом?

Eddy_Em ☆☆☆☆☆
()

Я думаю тебе нужно использовать realtime расширение, чтобы управлять задержками. Например, Linux PREEMPT_RT.

Moncruist
()

Меня ваша нулёвость просто поражает.

Если считать, что «воспроизведение» одного сэмпла уже написано, как реализовать считывание и нужные задержки между сэмплами? Временем обработки одного сэмпла, насколько понимаю, пренебречь нельзя, т. е. sleep(1/f) не сработает.

С чего не сработает? Ты реально не понимаешь, что каким бы время «обработки» твоего семпла не было, если оно меньше 1/f, то ты просто вызываешь его раз в 1/f.

Точнее у тебя не получится, ибо ядро тебе ничего не гарантирует. Хрен знает когда и как оно запишет твой семпл.

У тебя есть 2пути:

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

Надеяться, что твой обработчик выполняется за примерно оно время с минимальным разбросом. Это даст n-времени лага на каждый вызов. Т.е. вместо мигания через 1 2 3 4 5 - у тебя будет мигать через 1+n 2+n 3+n 4+n 5+n. Но этот лаг ты никогда не уберёшь, ты можешь лишь ускорением его как-то синхронизировать, не более.

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

anonymous
()
Ответ на: комментарий от Eddy_Em

Едик, ты меня даже порадовал. Молодец, мне аж смешно от того, что эта падаль тебе отвечает.

anonymous
()
Ответ на: комментарий от anonymous

Ты дегенерат. Не 2+n, а 2(1+n). Иначе нужно делать слип на 1/f-n, где n зависит от всего.

intelfx ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.