Při záznamu program c_rec
z VACu vytvoří soubor recording.c
, což je výsledný záznam, který se skládá z:
- recording.h, což je samotný výstup z programu c_rec a obsahuje především obrovský řetězec unsigned char tape_data[] a parametry záznamu:
- preemphasis_usec
- sample_rate_Hz
- mono
- seed – startovací pozice pseudonáhodného generátoru
- analogizen – počet digitálních symbolů
- analogizen_half – symbol na půl cesty – půlka počtu digitálních symbolů
- char_swap_rd – zpětná překladová tabulka pro 1-znakové přehrávání, aby data mohla být v ASCII artu, kde tichu odpovídají mezery atd.
- label0, label1, label2, label3 – jednotlivé řádky popisky kazety
- playback_gain_lin – je známý až po záznamu, tak je na konci. Zesílení při přehrávání.
- c_play1.c, první část přehrávače – proměnné
- pair1.h, definice konstant společných pro záznam o přehrávač: STRBASE, STR2BASE, STRBASE_HALF, STR2BASE_HALF
- ink_pixels.h: tabulka kolik inkoustových pixelů má který znak. Generováno programem count2
- pair2.h: kód překladových tabulek 1– a 2-znakového záznamu který musí být identický při záznamu i přehrávání, aby dával stejné výsledky, proto je v separátním souboru .h, který se vloží pomocí #include
- c_play2.c – většina kódu přehrávače
Čtení z kazety
V souboru c_play2.c read_byte_pretty_printed
pouze přečte bajt z řetězce tape_data
. Funkce compress_char
vyhodí z řady hodnot 3 znaky které se v C řetězcích nedají vždy napsat jako 1 znak: uvozovky, otazník a obrácené lomítko. Návratová hodnota 0 znamená že se další bajt z pásky nepodařilo přečíst a je tedy konec přehrávání.
static inline unsigned read_byte_clean(unsigned char *clean_byte) { unsigned retval; unsigned char expanded_char, compressed_char; retval=read_byte_pretty_printed(&expanded_char); if (!retval) return 0; compressed_char=compress_char(expanded_char); *clean_byte=char_swap_rd[((unsigned)compressed_char)&0xFFU]; /* int cannot be used because bitwise ops don't have guaranteed meaning in terms of value */ return 1; }
Přeskakování 3 problematických znaků
Proč se roztahování číselné řady na přeskočení uvozovky, otazníku a obráceného lomítka nedělal při záznamu? Záhadu objasní tyto komentáře v c_rec.c: pro zápis je tato operace integrována v překladové tabulce, pro čtení nikoliv.
static unsigned char char_swap_wr[STRBASE]; /* For recording. Contains directly expanded chars. */ static unsigned char char_swap_rd[STRBASE]; /* For playback. Indexed by compressed char. */
Máme-li odstup od šumu větší jak 41 dB, používají se místo toho dva znaky na symbol a tato rutina s překladovou tabulkou pair_rd, kterou si přehrávač vytoří identicky se záznamovým programem.
static inline unsigned read_pair(unsigned *zeroed_on_STR2BASE_HALF) { unsigned rv0, rv1; unsigned char ec0, ec1, cc0, cc1; rv0=read_byte_pretty_printed(&ec0); rv1=read_byte_pretty_printed(&ec1); if (!(rv0&&rv1)) return 0; cc0=compress_char(ec0); cc1=compress_char(ec1); *zeroed_on_STR2BASE_HALF=pair_rd[cc0][cc1]; return 1; }
Čtení diferenciální číslice
Obě funkce se pak sjednotí ve funkci čtení diferenciální číslice (symbolu) – tedy ne skutečného symbolu ale rozdílu od předchozího. STRBASE_HALF je symbol zhruba v půlce rozsahu pro 1-znakové nahrávání (zvládne max. 92 úrovní), STR2BASE_HALF je pro 2-znakové.
Zde je opět třeba zajistit, že před počítáním zbytku %n_levels
neprotočíme čísla pod nulu. Hodnota proměnné zeroed_on_STR(2)BASE_HALF
je v rozsahu >=STR(2)BASE_HALF-analogize_n_half...<STR(2)BASE_HALF-analogize_n_half+n_levels
.
Nulová změna sobě jdoucích symbolů odpovídá STR(2)BASE_HALF
v případě proměnné zeroed_on_STR(2)BASE_HALF
a ve výstupu toto bude odpovídat analogize_n_half
, což je zhruba půlka n_levels. Nejmenší hodnota která může být v zeroed_on_STR(2)BASE_HALF
je tedy STR(2)BASE_HALF-analogize_n_half
. K tomu se přičte analogize_n_half-STR(2)BASE_HALF
, takže dostaneme STR(2)BASE_HALF-analogize_n_half+analogize_n_half-STR(2)BASE_HALF
, a toto je očividně 0.
Pokud je obsah pásky porušen, podmínka splněna být nemusí, ale tam je pak jedno, co za hodnotu se z pásky přečte.
static inline unsigned read_diff_digit(unsigned long *diff_digit, unsigned long n_levels) { if (n_levels>STRBASE){ unsigned zeroed_on_STR2BASE_HALF; if (!read_pair(&zeroed_on_STR2BASE_HALF)) return 0; /* Now zeroed_on_STR2BASE_HALF is zeroed on (=corresponds to no change) STR2BASE_HALF. * >=STR2BASE_HALF-analogize_n_half...<STR2BASE_HALF-analogize_n_half+n_levels */ *diff_digit=((unsigned long)zeroed_on_STR2BASE_HALF+(unsigned long)analogize_n_half -(unsigned long)STR2BASE_HALF)%n_levels; return 1; }else{ unsigned char zeroed_on_STRBASE_HALF; if (!read_byte_clean(&zeroed_on_STRBASE_HALF)) return 0; /* Now zeroed_on_STRBASE_HALF is zeroed on (=corresponds to no change) STRBASE_HALF. * >=STRBASE_HALF-analogize_n_half...<STRBASE_HALF-analogize_n_half+n_levels */ *diff_digit=((unsigned)zeroed_on_STRBASE_HALF+(unsigned)analogize_n_half -(unsigned)STRBASE_HALF)%n_levels; return 1; } }
Z read_diff_digit
nám padají diferenciální symboly (číslice) tedy rozdíly vůči symbolu předchozímu. Skutečné symboly z nich udělá funkce read_smooth_11
a vytvoří z digitálních číslic analogové hodnoty voláním deanalogize_11
. Používá se proměnná previous_real_digit
, v které si pamatujeme hodnotu předchozí skutečné (nediferenciální) číslice a musí být v rozsahu >=0…<analogizen. Výraz (unsigned long)diff_digit+n_levels-analogize_n_half+*previous_real_digit
se nám neprotočí pod nulu, protože jediná odčítaná hodnota analogize_n_half
je menší přičítaná hodnota. n_levels=analogize_n
.
int read_smooth_11(unsigned long *previous_real_digit, double *smooth, unsigned long n_levels) { unsigned long diff_digit; unsigned long real_digit; if (!read_diff_digit(&diff_digit, n_levels)) return 0; real_digit=((unsigned long)diff_digit+n_levels-analogize_n_half+*previous_real_digit)%n_levels; *previous_real_digit=real_digit; *smooth=deanalogize_11(real_digit, n_levels); return 1; }
Je nutné aby proměnná previous_real_digit
byla inicializovaná na analogizen_half identicky jako při záznamu. Toto se dělá ve funkci read_tape_header
:
prev_real_dig_0=analogize_n_half; prev_real_dig_1=analogize_n_half;
Jak napovídala přípona _11
názvů read_smooth_11
a deanalogize_11
, pracovalo se v rozsahu reálných čísel >=-1…<=+1. To se triviálně mění ve funkci deanalogize_11
na rozsah >=0…<=+1: pro funkci deanalogize_01
.
Rádiový program: Hacker Public Radio 3811: pojmenované roury příkazem mkfifo (anglicky)
Myslím si, že k hackerskému rádiu dobře sedne, když je šířeno ve formátu programovacího jazyka C, a s vysílacím kompresorem zní lépe, skoro jako profesionální rádio. Tentokrát si prosvištíme slovíčka v angličtině.
_______________________________________________________ (+) _______________________________________________ (+) | / Hacker Public Radio ep. 3811: mkfifo and \ | | | named pipes, by Klaatu, CC-BY-SA 4.0 | | | | Have you ever named a pipe? | | | | https://hackerpublicradio.org/eps.php?id=3811 | | | | _________________________________ | | | | / _________ \ | | | | | A " A | | A " A | | | | | | ( ) | | | | ( ) | | | | | | v , v |_________| v , v | | | | | 75 μs \_________________________________/ | | | | | | | | VIRTUAL ANALOG CASSETTE BY KAREL KULHAVÝ | | | |_________________________________________________| | | / (+) \ | | / _ _ \ | | / _ (_) (_) _ \ | (+)_______/___(_)_______________________(_)___\_______(+) |
(logo public domain) |
Kompilační příkaz:
bzip2 -dc hpr_3811_256_fm.c.bz2 | cc -O3 -x c - -lm -o recording && ./recording 0 | mpv -
Zakomprimovaný zdroják ke stažení | Délka souboru zakomprimovaná | Odstup analogového signálu od šumu analogové nahrávky analogizované na digitální nosič | Preemfáze | Modulační procesor | Počet symbolů digitálního nosiče analogové nahrávky | Bitová rychlost ve zkomprimovaném stavu | Bitová rychlost zdroje | Délka min:sec | vzorkovací frekvence | Počet kanálů | Kvalita zdroje | SHA256 .c.bz2 souboru |
---|---|---|---|---|---|---|---|---|---|---|---|---|
hpr_3811_256_fm.c.bz2 | 14 586 150 B | 50 dB | 50 μs (evropské FM rádio) | SoX FM | 256 | 172 kbps | 1,15 Mbps | 11:19 | 44 100 Hz | mono | 24-bit WAV 48 kHz | 9C21299D0508B2208FACB46C90E44325 0B11CB0FE14191D97B560D63109FD10F |
hpr_3811_256_wam.c.bz2 | 9 803 039 B | 50 dB | 75 μs (AM rádio) | SoX AM | 256 | 116 kbps | 1,15 Mbps | 11:19 | 22 050 Hz | mono | 24-bit WAV 48 kHz | 409E2E9269164DF2F355C6C730761D92 44160D1315132E4DE481DC9FDE427978 |
hpr_3811_256_am.c.bz2 | 5 278 091 B | 50 dB | 75 μs (AM rádio) | SoX AM | 256 | 62 kbps | 1,15 Mbps | 11:19 | 11 025 Hz | mono | 24-bit WAV 48 kHz | 40917373A9E7A138BEEAF8C15975222C FC01FA1AF5ED83E8E4282FE2465F5696 |
Analogový rádiový poslech přímo z exotických krajin přinášený na vlnách jazyka C
Thajsko AM
Thajské či kambodžské analogové rádio si zde můžete v ukázce poslechnout zcela autenticky, aniž byste se tam museli osobně trmácet. Znít bude přesně stejně, jako byste se tam osobně dostavili (za předpokladu akustického šumu okolí podobného tomu na pásce) – po cestě žádná kvantizace ani psychoakustická komprese nebude. 16-bitovou kvantizaci KiwiSDR trapně zamlčím, škoda že KiwiSDR neumí více bitů. FM přijímač nahrávaný na 24-bitové zvukovce tím naštěstí netrpí (doufám že není ve smartphonu FM rádio implementováno digitálně).
Zda je AM preemfáze 75 μs v Thajsku povinná nevím, podle poslechu tipuju, že je přítomna, tak jsem příkazem SoX provedl deemfázi (2122 Hz=1/(2π*75μs)):
sox vstupni.wav vystupni.wav lowpass -1 2122
Do C jsem analogově nahrál Sabai Sabai z roku 1987 na KiwiSDR v Cha-Am, Thajsku na 675 kHz pravděpodobně 126 km přes hladinu moře z 5kW vysílače v Bangkoku. SDR v Cha-Am má trvalé prskavé rušení, slyšitelné v pozadí.
Thajská modlitba není v thajštině, ale v páli, jazyku původem z Indie, stejně jako v Kambodži. páli, příp. sanskrt, je pro tyto země totéž co latina pro Česko.
Kdybyste se divili, co má Čeština společného s Indií, když se říká, že je indoevropský jazyk, myslím, že tato tabulka hovoří sama za sebe:
čeština | páli nebo sanskrt |
---|---|
dvě | dvi |
dvě stě | dvi satau |
tři | ti |
třista | tisata |
čtyři | čatu |
čtyři sta | čatu sata |
deset | dasa |
smrt | mrť |
život | čivita |
věda | véda |
Pořad o domácích thajských receptech v angličtině byl vysílán svazkem na Evropu z Ban Dungu u Udon Thani v Thajsku na 9,920 MHz mezi 19:00Z a 20:00Z a odrazy mezi zemí a ionosférou oběhly 80 stupňů zemského povrchu. Překvapilo mě, v jak dobré kvalitě jsem ho chytil v Nizozemí na vzdálenost 8 895 km, ač vysílač vysílá pouze na 50 % výkonu, 250 kW místo 500 kW.
Softwarově definované rádio (SDR) v Cha-Am
Krátkovlnný 250 kW (max. 500 kW) vysílač Ban Dung, Udon Thani, Thajsko, dlouhý 1,8 km, který jsem v dobré kvalitě nahrál v Nizozemí na vzdálenost 8 895 km. Anténa je typu curtain array.
Detail vysílače Ban Dung, modré značky zleva doprava: 1. anténní pole směrem na Evropu, 2. vysokofrekvenční napájecí vedení k jednotlivým anténám, 3. budova vysílače
Nedaleko vysílače Ban Dung jsem byl v džunglově ostrovním klášteře Kham Chanot s jezerem, mostem, domečky pro duchy, tajemnou studánkou a gongem, co se dá rozeznít třením rukou.
_______________________________________________________ (+) _______________________________________________ (+) | / Thongchai McIntyre: Sabai Sabai (GMM Grammy) \ | | | Cha-Am SDR 28.4.2023 09:13:10Z 675 kHz | | | | https://www.youtube.com/watch?v=03xOU4xyYMo | | | | 30 s ukázka | | | | _________________________________ | | | | / _________ \ | | | | | A " A | | A " A | | | | | | ( ) | | | | ( ) | | | | | | v , v |_________| v , v | | | | | 75 μs \_________________________________/ | | | | | | | | VIRTUAL ANALOG CASSETTE BY KAREL KULHAVÝ | | | |_________________________________________________| | | / (+) \ | | / _ _ \ | | / _ (_) (_) _ \ | (+)_______/___(_)_______________________(_)___\_______(+) _______________________________________________________ (+) _______________________________________________ (+) | / Thajská modlitba v jazyce Páli, Cha-Am SDR \ | | | 28.4.2023 9:18:27Z 819 kHz | | | | 30 s ukázka | | | | | | | | _________________________________ | | | | / _________ \ | | | | | A " A | | A " A | | | | | | ( ) | | | | ( ) | | | | | | v , v |_________| v , v | | | | | 75 μs \_________________________________/ | | | | | | | | VIRTUAL ANALOG CASSETTE BY KAREL KULHAVÝ | | | |_________________________________________________| | | / (+) \ | | / _ _ \ | | / _ (_) (_) _ \ | (+)_______/___(_)_______________________(_)___\_______(+) _______________________________________________________ (+) _______________________________________________ (+) | / Radio Thailand World Service 9,920 MHz \ | | | 27.4.2023 19:03:42Z chyceno v Nizozemí UTwente | | | | WebSDR z 250 kW Ban Dung, Udon Thani, Thajsko | | | | Anglicky recepty thajská jídla 30 s ukázka | | | | _________________________________ | | | | / _________ \ | | | | | A " A | | A " A | | | | | | ( ) | | | | ( ) | | | | | | v , v |_________| v , v | | | | | 75 μs \_________________________________/ | | | | | | | | VIRTUAL ANALOG CASSETTE BY KAREL KULHAVÝ | | | |_________________________________________________| | | / (+) \ | | / _ _ \ | | / _ (_) (_) _ \ | (+)_______/___(_)_______________________(_)___\_______(+)
Kompilační příkaz:
bzip2 -dc sabai_92.c.bz2 | cc -O3 -x c - -lm -o recording && ./recording 0 | mpv -
Zakomprimovaný zdroják ke stažení | Délka souboru zakomprimovaná | Odstup analogového signálu od šumu analogové nahrávky analogizované na digitální nosič | Preemfáze | Modulační procesor | Počet symbolů digitálního nosiče analogové nahrávky | Bitová rychlost ve zkomprimovaném stavu | Bitová rychlost zdroje | Délka min:sec | vzorkovací frekvence | Počet kanálů | Kvalita zdroje | SHA256 .c.bz2 souboru |
---|---|---|---|---|---|---|---|---|---|---|---|---|
sabai92.c.bz2 | 251 118 B | 41 dB | 75 μs (AM rádio) | AM rádio | 92 | 67 kbps | 192 kbps | 0:30 | 12 kHz | mono | 12 kHz WAV 16-bit | 803611682B73096AA33FE46F240BF6B4 7A42F46934360B945751D8EDCA4C2184 |
sabai32.c.bz2 | 189 845 B | 32 dB | 75 μs (AM rádio) | AM rádio | 32 | 51 kbps | 192 kbps | 0:30 | 12 kHz | mono | 12 kHz WAV 16-bit | F80FDFA3E80A731676EBA04BA79A3C57 2784E6C23F37E4C5F3851968AEABE78D |
modlitba92.c.bz2 | 240 670 B | 41 dB | 75 μs (AM rádio) | AM rádio | 92 | 64 kbps | 192 kbps | 0:30 | 12 kHz | mono | 12 kHz WAV 16-bit | 51107B491E9593A675C8E6B0E3235DE2 BE994C2BCAEE81379F372FCFD533C01F |
modlitba32.c.bz2 | 176 747 B | 32 dB | 75 μs (AM rádio) | AM rádio | 32 | 47 kbps | 192 kbps | 0:30 | 12 kHz | mono | 12 kHz WAV 16-bit | EC24CCF80ACDC719C1DFF76849FE6BF1 F6D9CC71AB7759A05AEAB2EF0087FFB3 |
thajsko_v_nizozemi512.c.bz2 | 386 453 B | 56 dB | 75 μs (AM rádio) | AM rádio | 512 | 103 kbps | 228 kbps | 0:30 | 14 238 Hz | mono | 14 238 Hz WAV 16-bit | 845AD14B596729944AA10EB2A4051007 40B6891AC0BA7F7139A0ADAAEB18CD97 |
thajsko_v_nizozemi92.c.bz2 | 211 451 B | 41 dB | 75 μs (AM rádio) | AM rádio | 92 | 56 kbps | 228 kbps | 0:30 | 14 238 Hz | mono | 14 238 Hz WAV 16-bit | D918FF41BE9A2CC9BEB0256694DA7164 DACF6D8A226E82404A5A08D89124B0CE |
Příště budeme pokračovat v dekódování, až se nám analogový signál podaří dostat úplně ven.