Skip to content

Instantly share code, notes, and snippets.

View dmitriykovalev's full-sized avatar

Dmitriy Kovalev dmitriykovalev

View GitHub Profile

Decibel

bits 2 ^ bits dB (power) dB (amplitude)
1 2 3.01 6.02
2 4 6.02 12.04
3 8 9.03 18.06
4 16 12.04 24.08
5 32 15.05 30.10
6 64 18.06 36.12
import math
def print_audio_frames(num_samples, freq_hz, sample_rate_hz, num_channels):
for i in range(num_samples):
a = math.sin(2 * math.pi * freq_hz * i / sample_rate_hz)
print(f'{i // num_channels:4d} => ', end='')
for j in range(num_channels):
value = ((1 << (15 - j)) - 1) * a;
print(f'{int(value):6d}', end='')
print()

Quick Action: Play in mpv (macOS)

You need to have [mpv][mpv] installed. For example, you can run brew install mpv for that.

Run the built-in [Automator][automator] app and create a new "Quick Action". Name it "Play in mpv" and set it up according to the screenshot below:

  • Workflow receives current files or folders in any application
  • Input is entire selection
  • Image ▶ Play
import argparse
import hashlib
import math
import struct
import wave
def rms(samples):
return math.sqrt(sum(s*s for s in samples) / len(samples))
def md5(data):
@dmitriykovalev
dmitriykovalev / save-chrome-tabs.sh
Last active January 5, 2024 19:14
Save all chrome tabs to json file.
#!/bin/bash
osascript -l JavaScript > $(date '+%Y.%m.%d-%H.%M.%S')-chrome-tabs.json <<EOF
var app = Application('Google Chrome');
let result = app.windows().map((w) => {
return {
'name': w.name(),
'tabs': w.tabs().map((t) => {
return {'title': t.title(), 'url': t.url()};
from math import degrees, radians, tan, atan, sqrt
# Diagonal FOV
dfov = 90
# Sensor size
width, height = 4032, 3024
r = width / height
# Horizontal FOV (corresponds to width)
hfov = degrees(2 * atan(tan(radians(dfov / 2)) / sqrt(1 + 1 / (r*r))))
# Vertial FOV (corresponds to height)
@dmitriykovalev
dmitriykovalev / nv12_to_rgb.py
Last active August 14, 2025 13:13
Convert NV12 YUV image to RGB image using Python
import argparse
from PIL import Image
def nv12_to_rgb(nv12: bytes | bytearray, size: tuple[int, int]) -> Image:
w, h = size
n = w * h
y, u, v = nv12[:n], nv12[n + 0::2], nv12[n + 1::2]
yuv = bytearray(3 * n)
yuv[0::3] = y
yuv[1::3] = Image.frombytes('L', (w // 2, h // 2), u).resize(size).tobytes()
@dmitriykovalev
dmitriykovalev / python-argparse-check-range.md
Last active November 23, 2025 20:44
CheckRange class for the Python argparse module

Python: CheckRange for argparse

The Python argparse module lacks a built-in mechanism for validating argument ranges. For instance, while you can specify an argument type as int, there is no straightforward way to restrict it to only positive values. Similarly, when dealing with float arguments, there is no native method to ensure that the provided values fall within the range of [0.0, 1.0).

CheckRange is a possible solution to this problem. It is a subclass of argparse.Action. It allows you to validate open, closed, and half-open intervals. Each endpoint can be either a number or positive or negative infinity:

  • [a, b] → min=a, max=b
set -e
if [[ -f /.dockerenv ]]; then
exit 1
fi
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly DOCKER_IMAGE_TAG=$(docker build --quiet - <<EOF
FROM debian:bullseye
import argparse
import wave
def crop(src_filename, dst_filename, num_frames):
with wave.open(src_filename, 'rb') as src:
with wave.open(dst_filename, 'wb') as dst:
dst.setnchannels(src.getnchannels())
dst.setsampwidth(src.getsampwidth())
dst.setframerate(src.getframerate())