sppm_preemphasized() (Sample Peak Programme Meter) pouze měří sílu záznamu na pásce, abychom věděli, zda jsme nějaký vzorek nepřepálili a nemuseli ho ořezat, čímž by se náš vytříbený audiofilní čistě analogový HiFi zvuk s kabely z bezkyslíkaté mědi zkazil.
Slovo peak znamená že se měří okamžité hodnoty nikoliv průměr v určitém čase jak je to u VU metru, srovnání je ve výše uvedeném videu.
Potom se lišácky pouze rozsah –1…+1 přepočte na rozsah 0…+1, který chutná procesu analogizace, a vstoupí se do tomu příslušející rutinyemit_smooth_01() v souboru c_rec.c programu VAC:
static inline void emit_smooth_11(unsigned *old_real_dig, double smooth_11)
{
sppm_preemphasized(smooth_11);
if (!measure){
emit_smooth_01(old_real_dig, (smooth_11+1)/2);
}
}
Rutina emit_smooth_01() analogizuje analogovou hodnotu na digiální symbol. Ten potom odečte od předchozího digitálního symbolu. Tím se z dat vybouchá další entropie, protože vzorky mívají hodnoty podobné předchozím vzorkům, hodnoty signálu neskáčou po celém rozsahu náhodně. Tím se vytvoří statistické rozložení, které je nahromaděné kolem 0 a dobře se následně komprimuje pomocí bzip -9.
Chytře se přitom ještě využije cyklické nátury modulární aritmetiky, takže se nemusí téměř zdvojnásobit počet symbolů. Kdybychom měli 10 symbolů, museli bychom mít 19 symbolů pro rozdíly –10 až +10, ale protože cyklická modulární aritmetika jaksi funguje tam i zpátky tak se žádná informace neztratí a na konci vypadnou zase ta stejná data, co jsme dali na začátku, a žádnou větší sadu symbolů, která by mohla zkazit kompresi, nepotřebujeme.
Protože operace % nemá na záporných číslech ty vlastnosti, co potřebujeme, musíme se záporných číslům vyhnout, proto se tam různě přičítá analogize_n. analogize_n_half je polovička rozsahu symbolů: pokud se symboly nemění, generuje se jakási „nula“, která nemusí být přesně nula, když nula padne na půl cesty mezi dva symboly. To je z důvodu, aby neměnná křivka na ASCII artu vypadala jako samé mezery.
static inline void emit_smooth_01(unsigned *old_real_dig, double smooth_01)
{
unsigned long real_digit;
unsigned long diff_digit_low;
real_digit=analogize(smooth_01, analogize_n); /* Silence produces on average analogize_n_half or analogize_n_half+0.5 */
/* Here real digit >=0...<analogize_n */
/* This is where clipping would occur so let's do the SPPM here too */
diff_digit_low=(real_digit+analogize_n-*old_real_dig+analogize_n_half)%analogize_n;
*old_real_dig=real_digit;
emit_diff_digit(diff_digit_low);
}
Proces analogizace je standardní . Střídavý pseudonáhodný předmagnetizační signál analogizace se přičte, pak se kvantizuje, a v přijímači se potom tentýž pseudonáhodný signál odečte. Vzniklý kanál je doopravdy analogový, není to ani přidávání šumu ani dithering s distribucí chyby:
/* Returns 0...n_levels-1 */
static inline unsigned long analogize(double in_01, unsigned long n_levels)
{
double random_half_half;
random_half_half=generate_random_half_half();
return analogize_specify_prs(in_01, n_levels, random_half_half);
}
Funkce generate_random_half_half generuje pseudonáhodné číslo v rozsahu –0,5…+0,5 přičemž –0,5 tam být může a +0,5 ne. Používá se Marsagliův xorshift* 64 bitů. Dr. Marsaglia již tu s námi není, nicméně jeho pseudonáhodné generátory stále ano a fungují stejně dobře jako vždycky.
uint64_t prn=xorshift64s(state); return ldexp(prn, -64)-0.5;
Diferenciální digitální číslice – tedy diff_digit – jde do funkce emit_diff_digit(). Ta se rozhoduje, zda se číslice vejde do jednoho znaku na pásce nebo musí do 2. Protože 1 znak pojme maximálně 92 různých hodnot kvůli, které jsou čitelné na obrazovce a nemusí se zadávat jako víceznakové escape kódy.
static inline void emit_diff_digit(unsigned diff_digit_low)
{
/* C source code emit */
if (analogize_n>STRBASE){
emit_diff_digit_C2(diff_digit_low);
}else{
emit_diff_digit_C1(diff_digit_low);
}
}
Pro jednoznakový záznam (do 92 symbolů neboli 41 dB) je funkce emit_diff_digit_C1. Vstupní proměnná diff_digit_low je centrovaná na analogize_n_half což je digitální symbol zhruba v půlce rozsahu.
/* diff_digit_low is centered on analogize_n_half. */
static inline void emit_diff_digit_C1(unsigned diff_digit_low)
{
unsigned long diff_digit_STRBASE_HALF;
/* Constant signal level produces on average analogize_n_half and never goes out of >=0...<analogize_n */
diff_digit_STRBASE_HALF=(diff_digit_low+STRBASE_HALF-analogize_n_half)%STRBASE;
/* Constant signal level produces on average 128 */
byte2stdout_pretty(diff_digit_STRBASE_HALF);
}
STRBASE_HALF je definovaná v pair1.h takto:
#define STRBASE 92U /* Number of characters which can be included in a C string directly: 127-32-3 (\\, \?, \") */ #define STRBASE_HALF (STRBASE/2U)
Protože jsem v jednoznakové větvi, počet digitálních číslic pro analogizaci je maximálně 92 a tak analogize_n_half nemůže překročit STRBAS_HALF a hodnota výrazu diff_digit_low+STRBASE_HALF-analogize_n_half se nedostane nikdy do záporných čísel, takže před výpočtem zbytku po dělení %STRBASE nemusíme přičítat STRBASE.
diff_digit_STRBASE_HALF je teď centrovaná na STRBASE_HALF a funkce byte2stdout_pretty zajistí ASCII-artové formátování tak, že znak ticha STRBASE_HALF odpovídá mezeře, která nemá žádný inkoust, a znaky postupně se od této hodnoty nahoru i dolu vzdalující mají více a více inkoustu – jsou podle toho seřazeny. To se zajistí překladovou tabulkou char_swap_wr (wr jako pro zápis, přehrávač používá char_swap_rd), kterou si přehrávač s sebou nese.
V případě 2-znakového záznamu již překladová tabulka ve zdrojáku v nahrávce není, protože by byla příliš velká. Místo toho se generuje stabilním třídícím algoritmem, aby při záznamu i přehrávání byla spočítána přesně stejně.
static inline void byte2stdout_pretty(unsigned char c)
{
byte2stdout_dirty(char_swap_wr[(c)]);
}
Funkce byte2stdout_dirty nejdříve generuje obrácená lomítka na konci řádků a k nim i případně popisky sekundových značek, aby čtenář zdrojového kódu věděl, ke kterému času ono místo přísluší:
if (stdout_column+1+19>=COLUMNS){ // 1 for the data character, 19 for "/* 9999.999 s */"\ //
static unsigned long last_marker=0;
double second=(double)sampling_interval_counter/(double)sample_rate_Hz;
unsigned long marker=floor(second*markers_per_sec);
if (marker>last_marker){
printf("\"/* %.3f s */\"\\\n", second);
last_marker=marker;
}else{
fputs("\\\n",stdout);
}
stdout_column=0;
}
Zbytek funkce, který neukazuji, je tisk speciálních znaků do C-čkových řetězců, které se na pásce nevyskytují, pouze v popisce kazety, a normální znaky se s fanfárou do výstupu tisknou pomocí:
putchar(c);
Ukázkový poslech: Hacker Public Radio 3338: Používáme OpenSSL s_client jako telnet (anglicky)
Myslím si, že k hackerskému rádiu dobře sedne, když je šířeno ve formátu programovacího jazyka C, dokonce v ASCII-artu. A s vysílacím kompresorem zní lépe, skoro jako profesionální rádio.
_______________________________________________________ (+) _______________________________________________ (+) | / Hacker Public Radio ep. 3338: Using OpenSSL \ | | | s_client like telnet, by Klaatu, CC-BY-SA 4.0 | | | | s_client the new telnet. Here's how to use it. | | | | https://hackerpublicradio.org/eps.php?id=3338 | | | | _________________________________ | | | | / _________ \ | | | | | 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_3338_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_3338_256_fm.c.bz2 | 29 246 003 B | 50 dB | 50 μs (evropské FM rádio) | SoX FM | 256 | 197 kbps | 1,06 Mbps | 19:50 | 44 100 Hz | mono | 24-bit WAV 44 100 Hz | ECDEE4A64A6C7DB3CC19C906C1B3CD54 E4D00A6B5855580B0C66F8373E39A83A |
| hpr_3338_256_wam.c.bz2 | 19 133 008 B | 50 dB | 75 μs (AM rádio) | SoX AM | 256 | 129 kbps | 1,06 Mbps | 19:50 | 22 050 Hz | mono | 24-bit WAV 44 100 Hz | 2A554B8C0F9AC653120E3FD17BF7CCA4 BC8E7A0FE2BE30A7894D85CFF1A45ABB |
| hpr_3338_256_am.c.bz2 | 9 963 950 B | 50 dB | 75 μs (AM rádio( | SoX AM | 256 | 67 kbps | 1,06 Mbps | 19:50 | 11 025 Hz | mono | 24-bit WAV 44 100 Hz | F0AFA5794BC2489129C20162064E6384 1C91FCDC9612A86C33FA2A92DEB7B215 |
Delší hudební test: Euseng Seto | Walaubagaimanapun
GCC nás možná na řádku cca. 1,7 miliónů obšťastní hláškou, ta ale neznamená chybnou kompilaci:
recording.c:1692111: note: ‘-Wmisleading-indentation’ is disabled from this point onwards, since column-tracking was disabled due to the size of the code/headers
1692111 | *pretty_printed_byte=*read_head;
|
_______________________________________________________ (+) _______________________________________________ (+) | / euseng seto | walaubagaimanapun | CC-BY-ND \ | | | https://archive.org/details/bsc_051 Malaysian | | | | composer's piece driven by synth progressions, | | | | warm piano melodies and clinical glitches. | | | | _________________________________ | | | | / _________ \ | | | | | A " A | | A " A | | | | | | ( ) | | | | ( ) | | | | | | v , v |_________| v , v | | | | | 70 μs \_________________________________/ | | | | | | | | VIRTUAL ANALOG CASSETTE BY KAREL KULHAVÝ | | | |_________________________________________________| | | / (+) \ | | / _ _ \ | | / _ (_) (_) _ \ | (+)_______/___(_)_______________________(_)___\_______(+) |
Obal singlu Walaubagaimanapun (CC-BY-ND Euseng Seto) |
| 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
walaubagaimanapun_8464.c.bz2 |
79 245 863 B | 80 dB | 70 μs | žádný | 8464 | 521 kbps | 1,411 Mbps | 20:18 | 44 100 Hz | stereo | 16-bit WAV 44 100 Hz | A7C603EED25AD2ADD26AA7CC7036D81B 12BC8D9F843C29838C38AD4CE71F0EC7 |
walaubagaimanapun_fm_512.c.bz2 |
55 343 190 B | 56 dB | 50 μs (evropské FM rádio) | SoX FM | 512 | 364 kbps | 1,411 Mbps | 20:18 | 44 100 Hz | stereo | 16-bit WAV 44 100 Hz | E0A6CDB5AC4F02D3153D927C64BD1E6F E8D57F4BD475B373AE4694125E22D8FC |
Příště popíšeme strukturu zdrojového kódu, který je samorozbalovacím analogovým záznamem zvuku v jazyce C.


