在 C# 中通过 ffmpeg.exe 获取媒体文件的音频波形数据
以前这个功能我是通过 NAudio 实现的,需要把媒体文件的音频轨提取成单独的 WAV 文件才能获取到波形数据。即使借助 RAM Disk,速度也依然很慢。

忍受了一段时间后,昨天又搜了一遍 C# 下可用的音频处理类库,依然没有更好的选择。最后想到在视频转码和截图时常用的 mencoder, ffmpeg 等跨平台的命令行工具了。看了一下 ffmpeg 支持 stdout 输出,貌似可用。

最开始尝试了输出 WAV 格式的二进制流到 stdout,结果发现输出格式为 WAV 时,ffmpeg 会先在头部写一个占位的大小信息,在整个流输出结束后,再 seek 到那个位置改写大小信息 (来源)。这样当输出不是直接写入到文件,而是以 stdout 流直接输出时,这个改写操作就不能进行了,最后得到的 WAV 格式的数据流中的信息有错误,也就无法使用了。

使用 WAV 格式只是因为对它比较熟悉,毕竟是常见的最基本的直接存储型的音频文件格式了。但在翻阅 ffmpeg 文档后,发现它支持的格式非常多和灵活,可以选择直接输出整型或浮点数的波形数据,而不带额外的头信息。这正方便我用 C# 处理,最终我选择了最适用于后续处理的 Little Endian 32 位浮点数格式,也就是调用 ffmpeg.exe 时给定 "-f f32le" 参数。"-ar 44100 -ac 1" 参数则使输出固定为单声道 44100Hz 采样率的数据。

最后,完整的代码如下。Main() 方法中调用 ffmpeg.exe 将 test.mp4 的音频轨以单声道,44100Hz 采样率,32 位浮点数的形式输出到 stdout,由 ProcessStream() 对流 proc.StandardOutput.BaseStream 进行读取,最终由 ProcessBuffer() 方法获取每一个单精度浮点数。

  1. using System.Diagnostics;
  2. using System.IO;
  3.  
  4. // ...
  5.  
  6. static void Main(string[] args)
  7. {
  8.     // ...
  9.     string path = @"E:\Media\test.mp4";
  10.  
  11.     Process proc = new Process();
  12.     proc.StartInfo.FileName = @"E:\ffmpeg\ffmpeg.exe";
  13.     proc.StartInfo.Arguments = "-i \"" + path + "\" -vn -ar 44100 -ac 1 -f f32le -";
  14.     proc.StartInfo.CreateNoWindow = true;
  15.     proc.StartInfo.UseShellExecute = false;
  16.     proc.StartInfo.RedirectStandardOutput = true;
  17.     proc.StartInfo.RedirectStandardError = true;
  18.     proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
  19.     proc.Start();
  20.     proc.BeginErrorReadLine();
  21.     ProcessStream(proc.StandardOutput.BaseStream);
  22.  
  23.     proc.WaitForExit(10000); // 10s
  24.     if (!proc.HasExited)
  25.     {
  26.         proc.Kill();
  27.         Environment.Exit(1);
  28.     }
  29.     // ...
  30. }
  31.  
  32. static void proc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
  33. {
  34.     if (e.Data != null)
  35.     {
  36.         // Console.WriteLine(e.Data);
  37.         // do nothing
  38.     }
  39. }
  40.  
  41. static void ProcessStream(Stream stream)
  42. {
  43.     int didread;
  44.     int offset = 0;
  45.     byte[] buffer = new byte[sizeof(Single) * (1024 + 1)];
  46.  
  47.     int length, residual_length;
  48.  
  49.     while ((didread = stream.Read(buffer, offset, sizeof(Single) * 1024)) != 0)
  50.     {
  51.         length = offset + didread;
  52.         residual_length = length % sizeof(Single);
  53.  
  54.         if (residual_length == 0) {
  55.             ProcessBuffer(buffer, length);
  56.             offset = 0;
  57.         } else {
  58.             length -= residual_length;
  59.             ProcessBuffer(buffer, length);
  60.             Array.Copy(buffer, length, buffer, 0, residual_length);
  61.             offset = residual_length;
  62.         }
  63.     }
  64. }
  65.  
  66. static void ProcessBuffer(byte[] buffer, int length)
  67. {
  68.     int index = 0;
  69.     float sample_value;
  70.  
  71.     while (index < length)
  72.     {
  73.         sample_value = BitConverter.ToSingle(buffer, index);
  74.         index += sizeof(Single);
  75.         // to deal with sample_value
  76.     }
  77. }
  78.  
  79. // ...
当前语言: 中文 (简体) · also available in: English
音乐节拍跟踪演示视频
这些天写了一个基于 FPGA 和 ARM 的音乐节拍实时跟踪算法,FPGA 的 Verilog 代码写得差不多了,但后续 ARM 部分的处理就比较难搞一些。

算法的原型是用 MATLAB 的 M 代码写的,下面这个视频就是用的 MATLAB 里输出的结果进行的灯光效果展示。注意看的时候要选高清以上的清晰度,否则由于压缩的关系画面明暗会发生跳变。


目前来看这个算法的运算量和内存空间占用都太大了,也没能很好的达到预期效果,以后还得尝试换运算量小的算法。

下面这个是更早几天的视频,是上面视频中最后一首 True Romance 的节拍跟踪效果的预览视频。最开始打算写这个节拍跟踪算法就是因为这首歌,想把鼓和钢琴的节拍能同时展示出来。最终效果还是不令人满意。


当前语言: 中文 (简体) · also available in: English
《将 Windows 7 配置成 Windows XP 的样子》补图
将 Windows 7 配置成 Windows XP 的样子》一文写完后本应配上成果截图,但因懒得整理文件一直没做此项工作。现补上几张简单的截图:


桌面


开始菜单和任务栏


资源管理器


还是资源管理器


控制面板


Firefox
当前语言: 中文 (简体) · also available in: English
我的 DIY 常用器件列表
先将主要的 IC 部分整理出来了,剩余的还有二极管、BJT、MOS、开关、电位器和传感器。这些器件都是个人 DIY 时容易从淘宝上少量购买的,价格便宜且性能能满足一般要求。

点击元件型号可以直接在淘宝中搜索,默认按销量从高到低排序。点击型号右侧的 PDF 图标可以通过 Google 搜索 datasheet,用搜索引擎容易找到官方网站提供的最新的 datasheet。

IC - 电源管理

DC-DC
FP6291 1MHz 2.5A 升压电流模式 PWM 转换器 SOT23-6
AP2953A 3A 18V 同步整流降压转换器 SOP-8
MP2359 1.2A 24V 1.4MHz 降压转换器 SOT23-6
PT1301 0.8V 低启动电压升压 DC-DC 转换器 SOT-23-6, SOT-89-5
XR2203 1.2MHz 26V 升压 DC-DC 转换器 SOT23-5
LDO
AMS1117 1.3V(max) @ 800mA 压降, 800mA LDO SOT-223, TO-252
HT73XX 0.1V(typ) @ 40mA 压降, 静态电流 3.5uA, 低功耗 LDO SOT-89, TO-92
HT75XX 0.1V(typ) @ 1mA 压降, 最高 24V 输入电压 LDO SOT-89, TO-92
XC6206 0.7V(max) @ 100mA 压降, 200mA 小体积 LDO SOT-23, SOT-89, TO-92
MIC29302 0.6V(max) @ 3A 压降, 3A 大电流 LDO TO-220-5, TO-263-5
MIC5209 0.5V(max) @ 500mA 压降, 500mA LDO SOT-223, SOP-8, TO-263-5
隔离 DC-DC
B0505S-1W 5V 输入, 5V 输出, 1W DC-DC 隔离电源 SIP, DIP
B0505S-2W 5V 输入, 5V 输出, 2W DC-DC 隔离电源 SIP
VREF
TL431A 2.5V - 36V 电压基准, 30ppm/℃, 电流 1mA - 100mA SOT-23, TO-92
LM385-1.2 1.235V 电压基准, 30ppm/℃, 工作电流 10uA - 20mA SOT-23, TO-92, SOIC-8
LM385-2.5 2.5V 电压基准, 30ppm/℃, 工作电流 20uA - 20mA SOT-23, TO-92, SOIC-8
MC1403 2.5V 电压基准, 10ppm/℃, 输入电压 4.5V - 40V DIP-8, SOIC-8
充电
CN3058 500mA 磷酸铁锂电池充电器 SOP-8
TP4056 1A 线性锂离子电池充电器 SOP-8, MSOP-8
TP4057 500mA 线性锂离子电池充电器 SOT-23-6

IC - 线性

运放
LM358 0.7MHz 双运放, Vcc = 3V - 32V SOP-8, DIP-8
LM324 1.2MHz 四运放, Vcc = 3V - 32V SOP-14, DIP-14
MCP6002 1MHz RRIO CMOS 双运放, I = 100uA, Ib = 1pA(max) SOP-8, DIP-8
AD8605 10MHz 高精度低噪声 RRIO CMOS 运放, Vos = 65uA(max) SOT-23-5
AD8628 2.5MHz RRIO 斩波放大器, Vos = 1uV(typ) SOT-23-5
MAX4239 6.5MHz 斩波放大器, Vos = 0.1uV(typ) SOT-23-6, SOP-8
比较器
LM393 双比较器, Vcc = 2V - 36V SOP-8, DIP-8
LM339 四比较器, Vcc = 2V - 36V SOP-14, DIP-14
LM311 双高速比较器, Vcc = 3.5V - 30V SOP-8, DIP-8
麦克风放大
MAX9812LEXT 20dB 固定增益单输入麦克风放大器 SC-70-6
MAX9813LEKA 20dB 固定增益双输入麦克风放大器 SOT-23-8

IC - 数据采集

ADC
CS5343 24bit, 96kHz 音频 ADC, I2S 接口 TSSOP-10
TM7705 16bit Σ-Δ ADC SOP-16, DIP-16
CS5550 应用于电子秤的两通道 24bit Σ-Δ ADC SSOP-24
DAC
CS4344 24bit, 192kHz 音频 DAC, I2S 接口 TSSOP-10
TM8211 16bit 音频 DAC SOP-8

IC - 逻辑

逻辑门
74HC00 四 2 输入与非门 SOP-14, DIP-14
74HC04 六反相器 SOP-14, DIP-14
74HC14 六反相施密特触发器 SOP-14, DIP-14
74HC74 双 D 触发器 SOP-14, DIP-14
74HC138 3-8 译码器 SOP-16, DIP-16
74HC595 8 位串入/串出或并出移位寄存器 SOP-16, DIP-16
74HC245 8 位总线收发器 SOP-20, DIP-20
74LVC245 8 位总线收发器, 输入输出引脚可耐压 5V SOP-20
74LVC4245 8 位总线收发器, 输入输出引脚可耐压 5V, 双路电源 SOP-24, TSSOP-24

IC - 接口

收发器
MAX3232 3V - 5.5V RS-232 收发器 SOP-16, DIP-16
PL2303HX USB to RS-232 转换器 SSOP-28
模拟开关
74HC4051 8 通道多路复用器, Vcc = 2V - 10V SOP-16, DIP-16
74HC4052 双 4 通道多路复用器, Vcc = 2V - 10V SOP-16, DIP-16
74HC4053 三 2 通道多路复用器, Vcc = 2V - 10V SOP-16, DIP-16

IC - MCU

Cortex-M3
STM32F100C8T6B 中容量 24MHz MCU, 1×12bit ADC, 2×12bit DAC, 64KB Flash, 8KB SRAM LQFP-48
STM32F103C8T6 中容量 72MHz MCU, 2×12bit ADC, USB 2.0 FS, 64KB Flash, 20KB SRAM LQFP-48
STM32F103VBT6 中容量, 独立 VREF+ 引脚 72MHz MCU, 2×12bit ADC, 128KB Flash, 20KB SRAM LQFP-100
STM32F103VCT6 大容量, 独立 VREF+ 引脚 72MHz MCU, 3×12bit ADC, 2×12-bit DAC, I2S, SDIO, 256KB Flash, 48KB SRAM LQFP-100
MSP430
MSP430F149 8MHz MCU, 12bit 200ksps SAR ADC, 48 GPIOs, 60KB Flash, 2KB SRAM LQFP-64, TQFP-64
MSP430F2012IPW 16MHz MCU, 10bit 200ksps SAR ADC, 10 GPIOs, 2KB Flash, 128B SRAM TSSOP-14, DIP-14

IC - 存储器

SDRAM
H57V2562GTR-75C 256M (16Mx16bit) SDRAM, 133MHz TSOP-54
当前语言: 中文 (简体)
入手赛克 858D 热风拆焊台
买不买热风枪这个问题纠结了我两年多,因为这玩意买来后用的机会实在是太少了。业余做点东西不会选 BGA 封装的芯片,因此热风枪的用途就只剩拆元件了,还得是拆烙铁不好搞定的元件。

不过最近遇到几次需要拆 USB 插座和 LQFP 封装芯片的情况,没热风枪还真是很难弄,用烙铁拆很容易拆坏。因此决定买一个热风枪了,但毕竟用的机会还是很少,所以体积绝对不能大,这样不用的时候收到哪也省地。

在淘宝上搜了一圈,发现主要有四种热风枪类型。第一种是下面这种长的像电吹风的,看着就不像拆元件用的。



第二种是这种很便宜的 8032 便携式热风枪,电机、发热芯、调节旋钮都在手柄上,光看外观就有一股浓浓的山寨气息。应该不好用,也不耐用。



第三种是有气泵的 850 气泵式热风拆焊台,这种很专业了,很多人推荐。但是这种有气泵的拆焊台的最大问题就是体积太大了,顶部还有一个提手,想在上边摞一个 936 焊台都不行。非数显的型号是 850 或 850A,数显的型号是 850+ 或 850D 等。



第四种就是我最终选择的 858 无刷风机拆焊台,风扇和发热芯在手柄中,其余控制及电源电路在机箱中。非数显的型号是 858,数显的型号是 858D。



下面这个图片中标明了尺寸,13.0cm(H)*10.0cm(W)*14.7cm(L) 的体积和前面 850 的 13.5cm(H)*18.7cm(W)*24.5cm(L) 相比小了很多。可以直接摞在 936 焊台上,很节省空间。



下面是 858 热风台和 936 焊台摆在一块时的尺寸对比。



在确定 858D 这个型号后,还要考虑买哪个牌子的。在淘宝上搜“858D”按销量排序,排在前面的有谊华、安赛、安泰信、森沃、赛克和快克这几个牌子,快克的贵出一截直接排除了,听着耳生、价格也相对低的那几个牌子看评论有反映各种小问题的。最后在安泰信和赛克中选择了赛克,安泰信的评论中有点人反映加热时味道比较大,赛克的看着是没什么问题,另外比安泰信的还稍便宜点。

EEVBlog 的 David 评测过安泰信的 858D+ 热风台,他是在 2011 年时从中国买的,机器加运费一共 82 澳元,按当时的汇率合 500 多元人民币了。大陆当时淘宝上估计最多也就卖 200 吧,咱们这买这些设备价格还是很好的。
当前语言: 中文 (简体)
淘宝批量好评书签小工具
淘宝以前评论时一直有批量选择好评的复选框,但是大概从一年前开始就消失了,每次评论都得一个一个点好评。其实写个脚本也不麻烦,但一直懒得写。最近有个单子商品数量实在是太多了,在向淘宝客服确认现在确实没这个功能后,写了下面这段代码:

  1. function(){
  2.     var objs = document.getElementsByTagName('input');
  3.     for (var i = 0; i < objs.length; i++) {
  4.         var obj = objs[i];
  5.         if (typeof(obj.type) != 'undefined' && obj.type == 'radio') {
  6.             if (obj.className == 'good-rate') {
  7.                 obj.checked = true;
  8.             } else if (obj.name == 'description' || obj.name == 'attitude'
  9.                        || obj.name == 'delivery' || obj.name == 'logistics') {
  10.                 if (obj.value == '5') {
  11.                     obj.click();
  12.                 }
  13.             }
  14.         }
  15.     }
  16. }

把下面这个链接拖拽到标签栏,需要全部选好评时点一下就行了:

淘宝批量好评

如果想只批量评价商品,而不评论店铺的话,使用下面这个版本:

  1. function(){
  2.     var objs = document.getElementsByTagName('input');
  3.     for (var i = 0; i < objs.length; i++) {
  4.         if (typeof(objs[i].type) != 'undefined' && objs[i].type == 'radio' && objs[i].className == 'good-rate') {
  5.             objs[i].checked = true;
  6.         }
  7.     }
  8. }

要拖拽的链接是下面这个:

商品批量好评

我自己有一个本地的淘宝收藏夹程序,程序完成时同时写了 Greasemonkey 脚本和做了 Bookmarklet,后来淘宝的页面经过一次改动,Greasemonkey 脚本失效了,而 Bookmarklet 简单可靠,一直能用,因此这次只写一个 Bookmarklet。
当前语言: 中文 (简体)
解决开博尔 C5 网络播放器遥控接收范围过窄的问题
其实也算不上解决了,因为解决方式很暴力。不过对于由机器外壳设计时的硬伤所造成的问题,也想不出什么好办法了。

最开始其实我是怀疑遥控器的发射功率不够,但用万用表的电流档接一个 PD438B 光电二极管测试,这遥控器的发射功率比歌华机顶盒遥控器的还要大的多,因此肯定是接收端灵敏度或接收角度的问题了。

首先卸下底部的 4 个螺丝和后面的 3 个螺丝。底部有一个螺丝上有易碎贴,损坏会失去保修,不过这种东西真坏了也没修的必要了。



打开外壳上盖后,再试遥控器非常好用,远距离任意角度都没问题。从图片中可以看出机器的外壳比较厚,红外接收管前开的孔又不大,另外组装方式导致的红外接收管和前面的过滤片还有一点间距。这就是遥控接收范围很小的原因。



开始试了一下将红外接管与外壳贴紧,发现改善很小,就决定将前边的过滤片整个拆掉了。



这个过滤片是用胶水粘到外壳上的,粘得很牢,拆的时候用到了小电钻和斜口钳。拆得不完美,留下了点痕迹。



过滤片拆掉后从里面看是这样的,接收范围很广了。



从外面看是这样的,也不算太难看。

当前语言: 中文 (简体)
将 Windows 7 配置成 Windows XP 的样子 (同时关闭一些恼人的功能)
2013-09-03 添加: 上传了几张配置成果的截图,以下是其中一张:



---- 添加部分结束 ----

以下配置过程是我在配置 Windows 7 64-bit 系统的过程中记录下来的,仅供参考。

1. 系统保护 (可选)

  • 开始 -> 控制面板 -> 系统 -> 系统保护
  • System (C:), 配置..., 2% (1.20GB) (默认为 3%, 1.80GB)

2. 临时文件目录 (可选)

  • 开始 -> 控制面板 -> 系统 -> 高级系统设置
  • 高级 -> 环境变量...
  • 设置 TEMP, TMP = F:\Temp
  • 清除原来的文件 (%USERPROFILE%\AppData\Local\Temp, %SystemRoot%\TEMP)

3. 自动播放

  • 开始 -> 控制面板 -> 自动播放
  • 取消选中 "为所有媒体和设备使用自动播放"
  • 每个选择框保持默认的“选择默认值”

  • 运行 gpedit.msc
  • 用户配置 -> 管理模板 -> Windows 组件 -> 自动播放策略 -> 关闭自动播放 -> 在所有驱动器上启用
  • 计算机配置 -> 管理模板 -> Windows 组件 -> 自动播放策略 -> 关闭自动播放 -> 在所有驱动器上启用
  • (根据搜索结果,Shell Hardware Detection 服务应该保持启用)

4. 内置的 CD 刻录功能

  • 运行 gpedit.msc
  • 用户配置 -> 管理模板 -> Windows 组件 -> Windows 资源管理器 -> 移除 CD 刻录功能 -> 启用

5. 文件夹内容识别

  • 运行 Restore_Default_Folder_Templates.bat (下载)
  • 运行 All_Folders_Use_General_Items_Folder_Template.bat (下载同上)

6. Zip 文件夹

  • 运行 regedit
  • 删除下列键: (来源)
    对于 ZIP: HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}
    对于 CAB: HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}
    对于 ZIP Compressed (仅 Win7 64-bit): HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\ShellFolder
    对于 CAB (仅 Win7 64-bit): HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\ShellFolder

7. 分页文件 (可选)

  • 开始 -> 控制面板 -> 系统 -> 高级系统设置
  • 高级 -> 性能 -> 设置... -> 高级 -> 虚拟内存 -> 更改...
  • 设置为在 Cache (F:) 分区上,固定大小 2560MB
  • 重启

8. 休眠文件 (可选)

  • 运行 "powercfg -h off" 关闭休眠功能,以删除休眠文件
  • 对 System (C:) 分区进行碎片整理

9. 压缩软件

  • 安装 WinRAR 或 7-zip

10. Universal Theme Patcher

  • 运行 UniversalThemePatcher_20090409.zip 中的 UniversalThemePatcher-x64.exe
  • 重启

11. Luna 主题

  • 解压缩 luna_7_2_basic_by_welovexp-d3feion.rar (下载)

/*
12. 开始按钮 (忽略这条)

  • 运行 "7 to XP pack.zip" 中的 "Windows 7 Start Button Changer v 2.6.exe"
*/

13. Classic Shell

  • 运行 ClassicShellSetup_3_6_1.exe (不安装 Classic IE9 和 Update) (下载)
  • 配置

/*
14. 7+ Taskbar Tweak (忽略这条)

(该软件会导致在关机时 explorer.exe 崩溃)

  • 运行 7tt_setup.exe
  • 配置
*/

15. Shell Folder Fix

  • 运行 ShellFolderFixSetup.exe (下载)
  • 配置

16. 系统配置

  • 配置声音 (设置为无声)
  • 配置 Windows 颜色
  • 配置 Quick Launch Bar

17. 还原菜单项中热键的下划线

  • 开始 -> 控制面板 -> 轻松访问中心 -> 使键盘易于使用 -> 使键盘快捷方式使用更容易
  • 选中“给键盘快捷方式和访问键加下划线” (来源)

18. 任务栏

  • 右键点击任务栏 -> 属性
  • 任务栏 -> 任务栏按钮 -> 从不合并
  • 任务栏 -> 取消选中“使用 Aero Peek 预览桌面”
  • 「开始」菜单 -> 取消选中两个“存储并显示……”的复选框

19. WinSAT 计划任务

  • 开始 -> 控制面板 -> 管理工具 -> 任务计划程序
  • 计划任务程序库 -> Microsoft -> Windows -> Maintenance
  • 右键点击 WinSAT,选择“禁用”

20. 默认系统字体

  • 导入如下注册表文件: (来源)
    Windows Registry Editor Version 5.00

    ;Remove Segoe UI
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts]

    "Segoe UI (TrueType)"=""
    "Segoe UI Bold (TrueType)"=""
    "Segoe UI Italic (TrueType)"=""
    "Segoe UI Bold Italic (TrueType)"=""
    "Segoe UI Semibold (TrueType)"=""
    "Segoe UI Light (TrueType)"=""
    "Segoe UI Symbol (TrueType)"=""

    ;Font Substitution
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes]

    "Segoe UI"="Tahoma"
  • 重启

21. Windows 资源管理器 - 细节窗格

  • Windows 资源管理器 -> 组织 -> 布局
  • 取消选中“细节窗格”

22. Windows 资源管理器 - 组织栏

  • 在 Resource Hacker 中打开 Shellstyle.dll
  • How to Auto-Hide or Disable ... 这篇文章中所描述的修改。但是在第 5 步,使用 -50rp 代替原文中的 -28rp 来永久隐藏组织栏。代码就像这样:
    <Element padding="rect(0rp,0rp,0rp,-50rp)"/>
  • 重启
当前语言: 中文 (简体) · also available in: English
更多条目: [1]
« 上一页 · 下一页 »