Sed: полезные советы
Всем известен потоковый редактор sed.
Как мы его используем чаще всего? Взять регулярку и заменить что-то на что-то глобально.
$ seq 1 10 | sed 's/1/one/'
one
2
3
4
5
6
7
8
9
one0
Только этим можно не ограничиваться так как это очень мощная штука с условными переходами и промежуточным буфером хранения.
Как работает типичный флоу:
____ ----------------------- ----
|file| -> |прочесть строку в буфер| -> |line|
---- | (pattern space) | ----
^ -----------------------
| \/
| ----------------------- -------------
| | Выполнить команду 1 | -> |modified line|
| ----------------------- -------------
| \/
| ....
| \/
| ----------------------- -------------
| | Выполнить команду N | -> |modified line|
| ----------------------- | N-iteration |
| \/ -------------
| ----------------------- -------------
| | Записать результат | -> |modified line|
| ----------------------- | N-iteration |
| || -------------
| \/
| --------------------------
----| повторить до конца файла |
--------------------------
Под записью резльтата подразумевается не только вывод, но и запись в файл при in-place редактирвоании.
Стоп! А почему команд больше одной? Мы же с вам знаем только одно регулярное выражение?
Systemd: Перезагружаем pipewire после спячки
Начиная с Fedora 34 pipewire пришел на замену pulseaudio и стал довольно интересной альтернативой jackd. Так как теперь не требуется каких-либо телодвижений для того, чтобы все корректно заработало.
Конечно же без проблем не обошлось. В моём случае после спячки сервер перестает видеть докстанцию со встроенной звуковухой.
$ journalctl --user -u pipewire
...
дек 12 01:25:28 xxx pipewire[2846]: [E][000338392.259201][alsa-pcm.c:33 spa_alsa_open()] 'hw:Dock,1': playback open failed: Device or resource busy
дек 12 01:25:28 xxx pipewire[2850]: [E][000338392.261614][core.c:71 core_event_error()] core 0x56217c2f48e0: proxy 0x56217c42e9c0 id:72: bound:68 seq:1022 res:-16 (Device or resource busy) msg:"enum params id:3 (Spa:Enum:ParamId:EnumFormat) failed"
дек 12 01:25:28 xxx pipewire[2850]: [E][000338392.261651][media-session.c:1971 core_error()] error id:72 seq:1022 res:-16 (Device or resource busy): enum params id:3 (Spa:Enum:ParamId:EnumFormat) failed
...
В деве вроде бы проблему чинили, но в стейбле федоры - нет.
Единственный вариант, который приходит на ум - перезагружать сервер после спячки. Делать это каждый раз руками лень.
Сделаем сервис, который будет делать это за нас!
Однако, не все так просто. Проблема заключается в том, что systemd от пользователя запускается как отдельный процесс и не имеет доступа к системным таргетам вроде sleep/suspend и т.п.
Поэтому придется решать еще и эту проблему.
Кастомный sleep.target в юзерспейсе
- Скрипт
~/.local/bin/sleep_mon
#!/bin/bash dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Manager',member=PrepareForSleep" | while read x; do case "$x" in *"boolean false"*) systemctl --user --no-block stop sleep.target;; *"boolean true"*) systemctl --user --no-block start sleep.target;; esac done
- Таргет
~/.config/systemd/user/sleep.target
[Unit] Description=User level sleep target StopWhenUnneeded=yes
- Скрипт для активации таргета
~/.config/systemd/user/user-sleep.service
[Unit] Description=watch for sleep signal to start sleep.target [Service] ExecStart=%h/.local/bin/sleep_mon Restart=on-failure [Install] WantedBy=default.target
- Активируем и запускаем новый сервис
$ systemctl --user enable user-sleep.service $ systemctl --user start user-sleep.service
Непосредственно сам сервис для перезапуска pipewire
- Создаем файл
restart-pw.service
по пути~/.config/systemd/user
.[Unit] Description=Restart pipewire after resume StopWhenUnneeded=true [Service] Type=oneshot RemainAfterExit=true ExecStop=/usr/bin/systemctl --no-block --user restart pipewire pipewire-pulse [Install] WantedBy=sleep.target
- Добавляем юнит в запускаемые.
$ systemctl --user enable restart-pw.service
- Стартуем юнит
$ systemctl --user start restart-pw.service
- Можно посмотреть статус
$ systemctl --user status restart-pw.service
Литература:
MIDI: Превращаем сообщения в нажатия кнопок клавиатуры
Как конвертировать сообщения от midi-клавиатуры в нажатия кнопок на клавиатуре?
Где это может потребоваться - это в приложениях, которые не умеют в миди, но умеют в хоткеи. Например musescore - это приложение очень плохо умеет в миди.
Создадим простейший скрипт midi-to-keyboard. Все что он делает - это слушает события на шине и транслирует их в нажатия кнопок клавиатуры.
#!/usr/bin/env bash
THROTTLE=150
old_time=0
last_change=0
#aseqdump -p "Arturia MiniLab mkII" | \
aseqdump -p "System" | \
while IFS=" ," read src ev1 ev2 ch label1 data1 label2 data2 rest; do
current_time=$(($(date +%s%N)/1000000))
diff=$(($current_time-$old_time))
if [[ $diff -gt $THROTTLE && "$ch" = 15 ]]; then
# тротлинг событий обязателен
change=0
case $data1 in
48 ) # effects 1
if [[ $data2 -gt 64 ]]; then
xdotool key Right
change=1
elif [[ $data2 -lt 64 ]]; then
xdotool key Left
change=1
fi
;;
49 ) # effects 2
if [[ $data2 -gt 64 ]]; then
xdotool key Up
change=1
elif [[ $data2 -lt 64 ]]; then
xdotool key Down
change=1
fi
;;
esac
if [[ change -eq 1 ]]; then
echo "Change after $(($current_time-$old_time))"
old_time=$current_time
fi
fi
done
Литература:
PulseAudio: Перенаправление потоков аля jackd
Что мы хотим? Мы хотим подмешать к микрофонному сигналу еще что-то. Например дополнительный сигнал с другой звуковой карты для того, чтобы по скайпу с кем-то поджемить на гитаре\ударке.
В jackd это сделать довольно просто - там куча графических роутеров. Но что делать если надо подмешать сигнал в pulse?
Возьмем самый простой пример: нужно подмешать к звуку микрофона аудио из браузера.
mic -> skype <- ff
Просто так это работать не будет. Потребуется виртуальное loopback-устройство, которое будет смешивать сигналы, а после остальное по будет использовать его как микрофон.
skype ^ |mic -> loopback <- ff
1 - Создаем устройство
Создаем само устройство и задаем ему описание чтобы в панели управления бло что-то вразумительное, а не “Пустой выход”.
$ pacmd load-module module-null-sink sink_name=fx-sink 42 $ pacmd update-sink-proplist fx-sink device.description=Виртуальный_микрофон_вход $ pacmd update-source-proplist fx-sink.monitor device.description=Виртуальный_микрофон_выход
Цифру, которая выдает первая команда можно запомнить. Это идентификатор, по которому можно sink удалить.
2 - Перенаправляем микрофонный выход на это устройство
$ pactl load-module module-loopback source=alsa_input sink=fx-sink 43
Номер так же можно запомнить чтобы потом удалить ассоциацию.
Теперь в качестве устройства для ввода в панели управления (ставим как дефолтный девайс) или в программе выбираем fx-sink.monitor. Он будет называться “Виртуальный_микрофон_выход” (выше мы прописали в описании).
Чтобы посмотреть что писать в аргументе source просматриваем вывод команды
$ pactl list-sinks
Тут нам нужно найти содержимое поля name системного микрофона.
Источники:
Jackd: Измеряем задержку аудио сигнала в цепочке обработки
Не секрет, что большинство диванных музыкантов любят мериться минимальной задержкой своей звуковой карты считая, что это задержка сигнала от поступления на вход карты, прохождения через обработку и появления в мониторах.
Но что на самом деле означает эта задержка? Это лишь время, которое будет затрачено на обработку сигнала после поступления его в роутер (в моем случае в роли роутера выступает jackd).
А как измерить полную задержку вместе со временем на обработку и перевод сигнала в аналог?
jack_iodelay - утилита генерирует тестовый сигнал, который можно направить в роутере куда угодно, потом вернуть на вход этой же утилиты и посмотреть в консоли что получится.
Для измерения нам потребуется небольшой патч чтобы соединить один из входов интерфейса с выходом.
После этого запускаем утилиту, коммутируем нужный вход и выход в роутере и смотрим на результат в консоли.
Общая задержка составляет в среднем 820 фреймов. Чтобы узнать задержку в миллисекундах делим это число на частоту семплирования. (96кГц). Это 8,5мс.
Поле extra loopback latency содержит лаг, который был вызван ЦАП’ом и АЦП.
Задержка зависит и от настроек джека. От количества семплов и периодов на буфер
Для текущего теста 2 периода на буфер и 128 сэмплов. Итого 384. И ~430 фреймов - это задержка на железе. В сумме и получается ~820.
Можно пользоваться опциям -I и -O. Они отдельно позволяют посмотреть задержку по входу и выходу сигнала.