自己写了个 Windows 10 上用的快速启动栏,解决系统自带功能的对齐和缩放问题
在 Windows 10 上,当任务栏选择使用小按钮时,快速启动栏中的图标会有对齐和缩放问题:



而且缩放比例越高,问题越明显。(例如在 4k 分辨率下通常会使用 200% 以上的缩放比例)

所以我基于 WPF 和 DeskBand 写了一个自己的快速启动栏,可正确对图标进行对齐和缩放:



GitHub 项目地址是 https://github.com/wudicgi/Win10QuickLaunchBar

需要的小伙伴可以直接下载 release 压缩包使用。

PS, 写之前找了一圈示例程序,只找到 https://github.com/20154530/DeskBandTest 这个默认就能很好的自动缩放。所以最终是以这个项目为基础修改来的。
当前语言: 中文 (简体) · also available in: English
写了一个纯 C 语言版本的 Spleeter 人声、伴奏分离命令行程序
Spleeter 是 2019 年底 Deezer 公司开源的一个可以分离人声和背景音乐的程序 (也可分离出鼓、贝斯和钢琴),效果拔群。售价 400 刀的 RX 8 软件中的 Music Rebalance 功能,用的就是 Spleeter 的模型。

一年多过去了,现在 Github 上的 Spleeter 程序,包括官方原版程序,基本还都是需要有 Python 环境或者内部包含了一个 Python 的。C++ 的几个静态库和命令行程序,不是用了 CMake 就是只支持 Linux 系统。对 Windows 平台开发者不太友好,如果是一般用户想直接使用就更不方便了。

最近将我的 BeatShow 程序中用到 Spleeter 的部分代码整理了一下,形成了一个独立的纯 C 语言编写的 Spleeter 命令行程序。编译完就是一个 exe 程序,其余 dll 文件是 TensorFlow C API 和 FFmpeg 的动态库。可以直接运行使用,不需要 Python 环境。



Github 项目地址是 https://github.com/wudicgi/SpleeterMsvcExe

根据说明直接下载 release 文件就好。models 文件比较大,如果下载速度不给力可以试试 https://ghproxy.com/

早上在 v2ex 发了个分享帖,地址是 https://www.v2ex.com/t/776618
当前语言: 中文 (简体) · also available in: English
When We Disco 的 BeatShow 演示
最近被这首歌洗脑了,忍不住又录了个 demo. 现在业余时间一直在完善这个项目,主要功能基本都完成了,还剩下一些收尾工作,应该很快就能公开提供下载了。


在优酷上观看: https://v.youku.com/v_show/id_XNDg0ODgwMTMyMA==.html
在 bilibili 上观看: https://www.bilibili.com/video/BV1N64y1F73D
当前语言: 中文 (简体)
CH552 官方 USB HID 示例程序中的一处 bug
最近在开发 BeatShow 设备的固件恢复功能时发现,使用 CH552 实现的 USB HID 设备总是获取不到设备名称,而 STM32F072 的就没问题。即使将所有 USB 描述符都改成一样的,问题也仍然存在。

调试 PC 端程序看到底层调用的 HidD_GetProductString() 函数执行结果是成功的,只是返回的字符串长度为 0, 所以就得从硬件下手了。

经过抓包,发现对于 CH552 设备,除了设备枚举过程中的正常 GET_DESCRIPTOR 请求,在 PC 端程序调用 HidD_GetProductString() 时系统又发送了额外的 GET_DESCRIPTOR 请求。而且这些请求的返回数据长度只有 2 字节,明显是不正常的。

CH552 设备枚举过程中正常的 GET_DESCRIPTOR 请求, wLength = 0x00FF = 255:


CH552 设备完成枚举后的额外 GET_DESCRIPTOR 请求, wLength = 0x0102 = 258:


STM32 设备在完成枚举后则没有这些额外的 GET_DESCRIPTOR 请求:


对于为什么系统只对 CH552 设备发送了这些额外的 GET_DESCRIPTOR 请求,经过一番搜索没有找到答案。但显然 CH552 的程序在这块的处理上有 bug。

CH552 实现的 bootloader 是以 WCH 官方的 USB HID 示例程序 CompatibilityHID.C 为基础,逐步重构和修改而来的。这个示例中有一段处理 SETUP 事物的代码是这样的:

case UIS_TOKEN_SETUP | 0:                       // SETUP 事务
    len = USB_RX_LEN;
    if (len == (sizeof(USB_SETUP_REQ)))
    {
        SetupLen = UsbSetupBuf->wLengthL;
        len = 0;                                // 默认为成功并且上传 0 长度
        SetupReq = UsbSetupBuf->bRequest;
        // ...

可以看到只取了 wLength 的低字节部分 wLengthL 作为 SetupLen, 完全没有使用高字节部分 wLengthH。而另一个 VendorDefinedDev.C 示例程序中,就对高字节部分 wLengthH 做了检查:

case UIS_TOKEN_SETUP | 0:                       // endpoint 0# SETUP
    len = USB_RX_LEN;
    if (len == sizeof(USB_SETUP_REQ)) {         // SETUP 包长度
        SetupLen = UsbSetupBuf->wLengthL;
        if (UsbSetupBuf->wLengthH || SetupLen > 0x7F) SetupLen = 0x7F;      // 限制总长度
        len = 0;                                // 默认为成功并且上传 0 长度
        SetupReqCode = UsbSetupBuf->bRequest;
        // ...

CompositeKM.C 示例程序中也一样检查了 wLengthH:

case UIS_TOKEN_SETUP | 0:                       // SETUP 事务
    len = USB_RX_LEN;
    if (len == (sizeof(USB_SETUP_REQ)))
    {
        SetupLen = UsbSetupBuf->wLengthL;
        if (UsbSetupBuf->wLengthH || SetupLen > 0x7F)
        {
            SetupLen = 0x7F;                    // 限制总长度
        }
        len = 0;                                // 默认为成功并且上传 0 长度
        SetupReq = UsbSetupBuf->bRequest;
        // ...

CompatibilityHID.C 示例程序中原本没有任何字符串描述符,也没有对 GET_DESCRIPTOR 请求的处理代码,相关的内容都是我后添加的。这可能是官方程序中这个 bug 存在了这么长时间的原因。

知道原因后就好修改了,只要在 wLengthH 不为 0 时把 SetupLen 限制到 uint8_t 范围内的最大值 0xFF 就可以了:

case UIS_TOKEN_SETUP | 0:                       // SETUP 事务
    len = USB_RX_LEN;
    if (len == (sizeof(USB_SETUP_REQ)))
    {
        SetupLen = UsbSetupBuf->wLengthL;
        if (UsbSetupBuf->wLengthH != 0)
        {
            SetupLen = 0xFF;                    // 限制总长度
        }
        len = 0;                                // 默认为成功并且上传 0 长度
        SetupReq = UsbSetupBuf->bRequest;
        // ...
当前语言: 中文 (简体)
简单“修正”了一下 AStyle 中的一个重复缩进的问题
GitHub 地址: https://github.com/wudicgi/astyle-modified
效果对比脚本: https://github.com/wudicgi/astyle-modified/tree/master/bin
修改后程序下载: https://github.com/wudicgi/astyle-modified/blob/master/bin/AStyle.exe

1. 发现问题

上周我在对 ffmpeg 的 transcoding.c 示例程序进行代码风格美化时,发现 AStyle 在很多处不需要改动的地方添加了额外的缩进:

// 处理前
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
        args, NULL, filter_graph);

// 处理后
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
                args, NULL, filter_graph);

其实以前也遇到过这个问题,但这次出现得比较集中、比较多,就准备解决一下了。打开 AStyle 的 VS2017 项目进行调试,发现对于我使用的选项

indent=spaces=4
indent-after-parens
indent-continuation=2

AStyle 在遇到赋值运算符 '=' 时为后续行添加 2 级缩进,而当继续处理遇到左括号 '(' 时又添加了 2 级缩进,于是后续行就拥有了多余的 2 级缩进。

2. 修改问题

我使用了一个简单粗暴的方式进行修改,就是在 ASBeautifier 类的 registerContinuationIndent() 方法中添加一个条件判断,使它在已经因为 '=' 添加了后续行缩进的情况下,不再因为其后出现的第一个 '(' 再添加缩进。

void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
                                              int tabIncrementIn, int minIndent, bool updateParenStack)
{
    assert(>= -1);
    int remainingCharNum = line.length() - i;
    int nextNonWSChar = getNextProgramCharDistance(line, i);

    // if indent is around the last char in the line OR indent-after-paren is requested,
    // indent with the continuation indent
    if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
    {
        // added by Wudi
        bool noDuplicatedIndentForFirstParen = updateParenStack // current indentation is for opening paren '('
                && !continuationIndentStack->empty()            // previously indented for an assignment '='
                && parenIndentStack->empty()                    // current '(' is the first opening paren needs to add indentation
                && (!= 0);                                    // current '(' must not be the first char, otherwise there is no '=' ahead

        int previousIndent = spaceIndentCount_;
        if (!continuationIndentStack->empty())
            previousIndent = continuationIndentStack->back();

        int currIndent = continuationIndent * indentLength + previousIndent;

        // added by Wudi
        if (noDuplicatedIndentForFirstParen) {
            currIndent = previousIndent;
        }

        if (currIndent > maxContinuationIndent && line[i] != '{')
            currIndent = indentLength * 2 + spaceIndentCount_;
        continuationIndentStack->emplace_back(currIndent);
        if (updateParenStack)
            parenIndentStack->emplace_back(previousIndent);
        return;
    }

    // ...

3. 修改前后效果对比

对同样的一段代码进行处理,原版 AStyle 的输出为:

int ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
                args, NULL, filter_graph);

int (*enc_func_2)(AVCodecContext *, AVPacket *, const AVFrame *, int *) = (ifmt_ctx->streams[stream_index]->codecpar->codec_type ==
                AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;

ret = func(a, b, another_func(1, 2,
                        3),
                c, d);

修改后版本的输出为:

int ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
        args, NULL, filter_graph);

int (*enc_func_2)(AVCodecContext *, AVPacket *, const AVFrame *, int *) = (ifmt_ctx->streams[stream_index]->codecpar->codec_type ==
        AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;

ret = func(a, b, another_func(1, 2,
                3),
        c, d);

4. 修改的副作用

标题中的“修正”带引号是因为这并不一定是个 bug, 同时现在所做的这个修改会有一些副作用。对于一些极端情况的代码,例如:

int ret = func(a, b, another_func(1, 2,
3, 4, 5),
c, d)
/ 123;

原版 AStyle 能保留所有缩进等级,输出结果为:

int ret = func(a, b, another_func(1, 2,
                        3, 4, 5),
                c, d)
        / 123;

而该修改版本的输出为:

int ret = func(a, b, another_func(1, 2,
                3, 4, 5),
        c, d)
        / 123;

最外层在缩进等级上没有与内层区分开来。但像这样的代码并不常见,所以为方便自己日常使用,“修正”一下还是有必要的。

附: AStyle 原版链接

AStyle 的官方项目地址为 http://astyle.sourceforge.net/
当前语言: 中文 (简体)
开源一个剪贴板文本自动处理工具 Clipboard Auto Processor
这个工具最开始是 2016 年时写了个很粗糙的版本,只有自己一直在用。今年业余抽时间整理了一下代码,把原来设计的基础功能都补充完整了,感觉可以发一个 1.0 版本了。目标用户主要是程序员,可以自己编写脚本把平时一些重复性的文本处理操作自动化。

GitHub 地址: https://github.com/wudicgi/clipboard-auto-processor

考虑到 GitHub 上的图片经常加载不出来,把 readme 的所有内容直接贴这儿了。

1. 简介

Clipboard Auto Processor 是一个剪贴板文本自动处理工具。不同于一般的剪贴板增强软件只是管理历史内容,该工具可以自动调用任何脚本,来自动处理剪贴板中的内容。



脚本可以使用 PHP, Python 或 JavaScript 等任何您熟悉的语言来编写,只需实现从原始文本到所需结果的转换即可,其余工作均由 Clipboard Auto Processor 完成。

2. 使用方法

下载最新的 release 版本,解压到任意有写权限的位置,通常只要不放在 Windows, Program Files 或 C 盘根目录等路径下就可以。

首次运行 ClipboardAutoProcessor.exe 主程序时,程序会根据当前系统语言创建 config.ini 配置文件。之后可以修改该文件来设置脚本解释路径和显示字体等选项。

您可以手动创建快捷方式,放置到开始菜单中或桌面上。但是更推荐使用 Launchy, WoxKeypirinha 等快速启动工具,实现随时快速打开使用。



3. 示例脚本

转换文件路径列表中的反斜杠 (查看 JS, PHP, Python 脚本)



调整从 PDF 文档所复制文本的格式 (查看 PHP 脚本)



十六进制字符串到数组定义 (查看 PHP 脚本)



AStyle 代码风格美化 (查看 INI 配置文件)


当前语言: 中文 (简体) · also available in: English
更多条目: [1] [2] [3] [4] [5] [6] ... [27]
« 上一页 · 下一页 »