第 58 期:代码是否越简洁抽象越好

@Author : Lewis Tian (taseikyo@gmail.com)

@Link : github.com/taseikyo

@Range : 2024-04-07 - 2024-04-13

Weekly #58

readme | previous | next

本文总字数 3991 个,阅读时长约:6 分 22 秒~12 分 43 秒,统计数据来自:算筹字数统计

*Photo by Ulrich & Mareli Aspeling on Unsplash

不缘天上云龙会,谁解湘南𧑐蚌持? —— 刘三吾《湘南杂咏三首 其一》

Table of Contents

  • review

    • url 短链设置广告追踪 cookie

  • tip

    • 用 ffmpeg 合并音频文件

    • 如何生成键盘输入统计看板

  • share

    • 代码是否越简洁抽象越好

algorithm 🔝

review 🔝

作者介绍他使用短链的经历,在短链被重定向到真正链接之前,被广告公司设置了 cookie,而这些 cookie 能在使用其广告技术的所有其他网站上跟踪:

$ curl -v https://tinyurl.com/examplezoom
...
> GET /examplezoom HTTP/2
> Host: tinyurl.com
...
< location: https://redirect.viglink.com?key=a7e37b5f6ff1de9cb410158b1013e54a&u=https%3A%2F%2Fzoom.us%2Fj%2F123456789&prodOvrd=RAC

$ curl -v 'https://redirect.viglink.com?key=a7e37b5f6ff1de9cb410158b1013e54a&u=https%3A%2F%2Fzoom.us%2Fj%2F123456789&prodOvrd=RAC'
> GET /?key=a7e37b5f6ff1de9cb410158b1013e54a&u=https%3A%2F%2Fzoom.us%2Fj%2F123456789&prodOvrd=RAC HTTP/1.1
> Host: redirect.viglink.com
...
< Set-Cookie: vglnk.PartnerRfsh.p=; Domain=.viglink.com; Path=/; SameSite=None; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure
< Set-Cookie: vglnk.Agent.p=v-c935c520ecc561fe60a9418874e023b7; Domain=.viglink.com; Path=/; SameSite=None; Expires=Mon, 01 Feb 2021 16:52:34 GMT; Secure

果然是只要有盈利的地方,就有空子钻。

tip 🔝

1、问题描述

打电话的对话,被拆分成了两个 PCM 文件。其中主叫的录音文件 A.pcm,被叫的录音为 B.pcm。

问题是怎么合成一个混音的对话文件 AB.wav。

2、WAV 文件的录音格式

常见的声音文件主要有两种,分别对应于单声道(11.025KHz 采样率、8Bit 的采样值)和双声道(44.1KHz 采样率、16Bit 的采样值)。

采样率是指:声音信号在“模→数”转换过程中单位时间内采样的次数。采样值是指每一次采样周期。WAVE 文件数据块包含以脉冲编码调制(PCM)格式表示的样本。WAVE 文件是由样本组织而成的。在单声道 WAVE 文件中,声道0代表左声道,声道1代表右声道。在多声道WAVE文件中,样本是交替出现的。

WAV 文件的格式:

endian
field name
Size
说明
计算方式

big

ChunkID

4

文件头标识,一般就是 "RIFF" 四个字母

ASCII 码表示的 “RIFF”。(0x52494646)

little

ChunkSize

4

整个数据文件的大小,不包括上面 ID 和 Size 本身

36+SubChunk2Size,或是 4 + (8 + SubChunk1Size) + ( 8 + SubChunk2Size ),这是整个数据块的大小(不包括 ChunkID 和 ChunkSize 的大小)

big

Format

4

一般就是 "WAVE" 四个字母

ASCII 码表示的 “WAVE”。 (0x57415645)

big

SubChunk1ID

4

格式说明块,本字段一般就是 "fmt"

新的数据块(格式信息说 明块)ASCII 码表示的 “fmt”—— 最后是一个空格。(0x666d7420)

little

SubChunk1Size

4

本数据块的大小,不包括 ID 和 Size 字段本身

本块数据的大小(对于 PCM,值为 16)。

little

AudioFormat

2

音频的格式说 明

PCM = 1 (比如,线性采样),如果是其它值的话,则可能是一些压缩形式

little

NumChannels

2

声道数

1 => 单声道

little

SampleRate

4

采样率

采样率,如 8000,44100 等值

little

ByteRate

4

比特率,每秒所需要的字节数

等于 : SampleRate * numChannels * BitsPerSample / 8

little

BlockAlign

2

数据块对齐单元

等于:NumChannels * BitsPerSample / 8

little

BitsPerSample

2

采样时模数转换的分辨率

采样分辨率 ,也就是每个样本用几位来表示,一般是 8bits 或是 16bits

big

SubChunk2ID

4

真正的声音数据块,本字段一般是 "data"

新数据块,真正的声音数据。ASCII 码表示的 “data “(0x64617461)

little

SubChunk2Size

4

本数据块的大小,不包括 ID 和 Size 字段本身

数据大小,即,其后跟着的采样数据的大小。

little

Data

N

音频的采样数据

真正的声音数据

3、查看录音的 PCM 文件

# pcm转立体声mp3
ffmpeg -i input1.pcm -i input2.pcm -filter_complex "amovie=input1.pcm [l]; amovie=input2.pcm [r]; [l] [r] amerge" output.mp3

# amr转混音amr
ffmpeg -i input1.amr -i input2.amr -filter_complex amix=inputs=2:duration=longest  -ab 12.2k -ar 8000 -ac 1 output.amr

# 在后面加上 -loglevel quiet -y, 可以覆盖输出文件,避免输出日志,如:

ffmpeg -i input1.amr -i input2.amr -filter_complex amix=inputs=2:duration=longest  -ab 12.2k -ar 8000 -ac 1 output.amr -loglevel quiet -y

4、测试效果

4.1、1.amr 和 2.amr 是左右声道的录音,现在合成混音 1_2.amr

ffmpeg -i 1.amr -i 2.amr -filter_complex amix=inputs=2:duration=longest:dropout_transition=2  -ab 12.2k -ar 8000 -ac 1 1_2.amr

4.2、1.wav 和 2.wav 是左右声道的录音,现在合成立体声 1_2.mp3,即左声道是 1 的声音,右声道是 2 的声音。

ffmpeg -i 1.wav -i 2.wav -filter_complex "amovie=1.wav [l]; amovie=2.wav [r]; [l] [r] amerge"  1_2.mp3

4.3、双声道的pcm转换为单声道的amr,指定编解码器

ffmpeg -y -f s16le -ar 8000 -ac 2 -i 1.pcm -acodec amr_nb -ab 12.2k -ar 8000 -ac 1 1.amr

其实这个东西也不难,就是监听键盘的输入并保存,然后使用一个可视化框架将其可视化即可。

share 🔝

1. 代码是否越简洁抽象越好

  • https://overreacted.io/goodbye-clean-code/

上面的文章讲述了作者的重构代码的经历,将同时重复冗余的代码进行了精简重构,结果他老板让他把代码改回了老版本。这里就引出一个话题:代码是否越简洁抽象越好?

很显然,如果是自己维护的代码,自己知道其逻辑,当然是越简洁抽象越好的,但是作为公司的某个产品,你要知道维护这个代码的是你与你的同事,如果你高度简洁抽象,代码确实减少了,但是理解成本却大大提升了,随着人员变动,新来的同事需要去花费很多时间去理解原来的代码逻辑,从公司层面来讲,这显然是得不偿失的。即便某款产品背后是一堆屎山代码,但是它能跑,能给用户提供服务并且未出错,它就是好的不是吗?

readme | previous | next

最后更新于

这有帮助吗?