Air 系列应用交流/AirDaw(from Ardour)|AirDaw · 鸿蒙 PC 适配全记录

AirDaw(from Ardour)|AirDaw · 鸿蒙 PC 适配全记录

【Air 系列 · 鸿蒙 PC 适配全记录】09 / 56

■ 应用:AirDaw(from Ardour)(AirDaw)
■ 定位:Ardour 移植,数字音频工作站
■ 上游:Ardour 9.7.0 | 路线:GTK2+GDK2 后端 | 版本:1.1.0
■ 开源: https://gitcode.com/Andy88/Harmony-Ardour
■ 市场状态:已上架 AGC 应用页: https://appgallery.huawei.com/app/6917614382579768287
■ 官网(免费下载): https://www.shunidc.cn/

————————————————————
开源鸿蒙 PC 社区: https://harmonypc.csdn.net/

PC 社区项目申请: https://atomgit.com/OpenHarmonyPCDeveloper

适配开源地址:https://gitcode.com/Andy88/Harmony-Ardour

环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743

▍一、为什么要适配 AirDaw

Ardour 是开源世界最重要的数字音频工作站(DAW)之一:多轨录音、非线性编辑、混音、走带、插件与导出,全部围绕 GTK2 + gtkmm2 的界面与自研会话引擎构建,以 waf 组织构建。DAW 代表了桌面应用的一个极端——窗口数量多、控件密度高、对输入语义与渲染时序的要求苛刻。把这样的软件带到鸿蒙 PC,检验的不是单个功能点,而是整套 GTK 绘制模型、事件模型与窗口模型能否在新窗口系统上重建。

AirDaw 采用的路线与 Qt 系工程不同:不走 Qt QPA,而是保留 Ardour 的 GTK 栈,自研一套 OHOS GDK2 后端让 GTK2 直接在鸿蒙窗口系统上绘制——这与 AirGimp 建立的 GTK 移植范式同源,后端从 AirGimp 的 GDK3 版移植改写,并以 directfb 后端为 GDK2 蓝本。工程同时维护了 40 余篇 ai_log 逐轮实录与 PORTING.md 踩坑记录(D6-D24),每一轮修复都有真机取证。

当前工程的应用名为 AirDaw,包名 com.airdaw.app,版本 1.0.0,deviceTypes 覆盖 phone、tablet 与 2in1,Ability 固定横屏。测试设备覆盖三种形态:HUAWEI MatePad Mini、MatePad 11.5(v45 起主验证机)与 HUAWEI MateBook Pro(2in1 PC,v13 起双端回归)。PORTING.md v11 轮记载全链可用时 HAP 约 176MB。

▍二、先划清边界:不把编译通过当成适配完成

Ardour 在 Linux 桌面上的每一层都依赖 X11 生态:GDK 的 X11 后端加窗口管理器管理多顶层窗与 z 序,JACK/ALSA/PulseAudio 提供音频,GtkFileChooser 弹本地文件对话框,用户目录随便写。鸿蒙侧这些前提全部不存在——没有窗口管理器,没有 JACK,沙箱限制写路径。AirDaw 的边界划分是:渲染与窗口模型用自研后端加 ArkTS 合成层重建,音频后端先以 dummy 保 UI 全链贯通(OHAudio 后端登记在依赖矩阵与 M3 里程碑中,当前构建为 --with-backends=dummy),文件选择整体拦截到系统 Picker,会话存储迁入沙箱。

层次 原项目实现(或传统桌面方案) 鸿蒙侧当前方案
窗口系统 GDK X11 后端 + 窗口管理器 自研 gdk-ohos2 后端 + ArkTS 合成(TEXTURE 型 XComponent)
进程形态 独立进程跑 GTK 主循环 libairdaw_core.so GTK 线程宿主 + NAPI 桥
菜单/顶栏 GTK 菜单栏原样渲染 ArkTS 原生标签栏与菜单面板(快照 + 命令回注)
音频后端 JACK / ALSA / PulseAudio dummy(当前构建);OHAudio 后端为规划项
文件选择 GtkFileChooser 本地弹窗 拦截 → ArkTS 系统 Picker(OPEN/导出通道)
会话存储 用户目录自由路径 沙箱 files/ardour/sessions/ + 存量配置迁移
文案语言 en 上游 + 各语言 po zh_CN .mo 落地 + manifest CRC32 指纹 + 定向补译

这条边界中最需要说清的是音频:当前产物没有真实录音与回放,v25 轮曾将用户报障"泛音速度慢"定案为"反应慢"的谐音误读——全工程零音频实现。UI、会话、编辑与走带链路是真实的;声音通路是后续里程碑。

▍三、鸿蒙版的整体架构

工程是 Air 双层架构的 GTK 版:ArkTS 壳负责 splash、沉浸式、原生标签栏(走带控制)、系统文件 Picker 与 rawfile 会话数据部署,XComponent 用 TEXTURE 型;NAPI 薄桥 libdawbridge.so 之下是 libairdaw_core.so 宿主,GTK 线程、gettext 环境与 SIGSEGV 取证都在其中;GTK2 挂在自研 OHOS GDK2 后端上,Ardour 库与 gtk2_ardour GUI 经 waf 交叉编译。

text
EntryAbility(横屏窗口 / 沉浸式 / want 命令通道)
├── Index.ets:XComponent(TEXTURE) + 顶栏标签栏 + 菜单面板 + DialogHost 浮层
├── DialogPage.ets:对话框子窗页(自由多窗形态)
├── ImmersiveManager.ets:藏栏沉浸 / topAvoidPx 采集 / 键盘避让策略
└── napi_init.cpp:NAPI 桥(surface / 输入注入 / IME / contentInset / 会话命令)
libairdaw_core.so(GTK 线程宿主 + env/gettext/SIGSEGV handler)
├── GTK2 + 自研 gdk-ohos2 后端(gdk/ohos)
│ ├── 复用 AirGimp 栈:glib / cairo / pango / gdk-pixbuf / freetype / fontconfig
│ └── 新编:gtk2 + sigc++2 + glibmm-2.4 + cairomm-1.0 + pangomm-2.4 + gtkmm-2.4
├── Ardour libs(pbd/evoral/temporal/ardour/canvas/gtkmm2ext …,waf 交叉)
├── gtk2_ardour(GUI,GTK 主循环跑在 core 宿主线程)
└── 音频后端:dummy(OHAudio 后端为 M3 规划项,MIDI 用 dummy)


主要目录如下:

text
AirDaw/
├── AppScope/app.json5 # 包名 com.airdaw.app、版本 1.0.0
├── PORTING.md # 移植手册:逐轮记录、架构、风险册、踩坑 D6-D24
├── ai_log/ # 40 余篇逐轮实录(v3-v45)
├── entry/src/main/
│ ├── ets/
│ │ ├── pages/Index.ets # 壳层主页面:XComponent + 顶栏 + 菜单
│ │ ├── pages/DialogPage.ets # 对话框子窗页
│ │ ├── components/DialogHost.ets# 浮层卡片对话框
│ │ └── managers/ImmersiveManager.ets
│ └── cpp/napi_init.cpp # NAPI 桥(id 前缀契约、输入、IME、inset)
└── native/
├── src/Ardour-9.7.0/ # 上游工作树(waf 交叉构建)
├── patches/ # gtk2-ohos / ydk-ohos / ardour-compat 补丁集
├── scripts/ # env.sh / build_gtk2 / build_ardour / build_core / deploy_daw
└── install/ # 依赖与产物安装前缀


▍四、核心适配过程

### 1. 自研 OHOS GDK2 后端

GDK2 与 GDK3 的 API 面差异大,工程以 directfb 后端为结构蓝本,把 AirGimp 已验证的 GDK3 OHOS 后端逻辑移植改写为 gdk/ohos:窗口实现(GdkWindowImplOHOS)、显示实现、输入事件合成与 surface 生命周期管理全部自持。X11 语义被逐条翻译到无窗口管理器的环境:expose 的服务端预清背景语义(clear_region_internal 的 __OHOS__ 分支)、copy_area 的旧区像素跨 resize 存活语义、命中测试的递归下钻语义。核心与 GTK 主循环一起跑在 core 宿主的专有线程里,与 ArkTS 之间只经 NAPI 通道往来。

### 2. 渲染合成链与呈现纪律

多 toplevel(主窗 + 各对话框 + 弹出菜单)由后端统一 z 序合成到 TEXTURE 型 XComponent。这条链经历了多轮重构:v14 引入 present 合批与 compose 缓存,根治逐块上屏与装载风暴丢绘,对话框呈现入队改深拷贝消除切页撕裂;v15 用 switch-page 事件驱动的分档锁帧(小窗 800ms、大窗 1600ms)消灭切页首帧半成品;v23 落地脏区合成并保留 AIRDAW_FULL_COMPOSE 开关;v38 引入就绪驱动的 compose hold——过渡期累计损伤面积超 85% 屏幅且轮数达标即早释,对话框 hide 延迟跟随 hold 实际存否。每一步都以连拍帧序列做定量验收。

### 3. 输入注入的语义完整化

触摸/鼠标事件从 ArkTS 注入后必须复刻 X11 的完整语义,工程踩坑记录沉淀了这套规则:命中测试要经 gdk_ohos_deepest_at 递归下钻到最深子窗并逐层 parent-relative 换算(D19,否则"大量按钮点不中");press 必须隐式抓取到 release,防 1-5px 抖动让按下与抬起落进不同子窗(D20);子窗级 crossing 必须合成 ENTER/LEAVE,否则 ArdourButton 的 hover 激活门永远不开(D21);自动化点击要同点快击,1000ms 按压会被判长按(D24)。v45 又为触屏补上长按→button3 的合成状态机(500ms/24px slop/多指取消),并把双击判定从 GDK 默认的 250ms/5px 放宽到 400ms/30px 以适应手指节奏。

### 4. ArkTS 壳通道:顶栏、Picker、IME 与沉浸

壳层承担 GTK 不该再管的系统交互:顶部标签栏与走带控制是 ArkTS 原生组件,经 NAPI 命令通道驱动 GTK UI 动作;GtkFileChooser 被拦截转接系统 Picker,OPEN、保存与导出通道直达(v41);IME 采用 KeyboardAvoidMode.NONE 加浮层卡片手动上移(允许负 y)的方案,输入件坐标随 ime-show 附带,几何回声免钳;contentInset 经 NAPI 缓存回放防早到静默丢弃(v25)。沉浸式经两轮实验定案:用户裁决"状态栏可见的边到边不叫沉浸",v40 回归藏栏方案——FULL_SCREEN 分支采集真实栏高并入 topAvoidPx(90px 地板)后隐藏状态栏,不调 setWindowLayoutFullScreen,避开 GestureTopBar 吞触摸与避让翻零两个已实证的坑。

### 5. 会话沙箱化与汉化体系

v36 把会话迁入沙箱 files/ardour/sessions/,存量配置的 default-session-parent-dir 随之迁移(core 日志 config migrated 实证);导出适配 DOWNLOAD 目录型 URI 的返回形态;二次打开走「擦除会话」确认的上游保护语义被如实保留。汉化是一条工程化流水线:zh_CN po + gtk20.mo 落地约 90 条翻译起步,manifest 以 CRC32 指纹判定重部署,后续补译与误译勘正(如 SyncSource|Int. 误译「中断」改「内部」)都走定向改译加 CRC 刷新;上游去品牌用 mo 定向改译与图标全系替换完成,同时保留 ardour_home 等功能性标识不破坏存量兼容。

▍五、适配中遇到的几个难点

### 难点一:没有窗口管理器的渲染契约

X11 应用默认窗口管理器会补齐的事件与失效行为,在鸿蒙侧都要 GDK 后端自己兑现。v21 把"渲染缺失族"定案为四层根因:client-side 子窗重映射无失效(D12,旧像素滞留新内容永不画)、toplevel move_resize 不同答 CONFIGURE 就永久冻结(D13,GTK 每个顶层 resize 请求都会冻结更新等回声,同尺寸请求也冻结)、事件源只查注入队列饿死公共队列事件(D14)、动态显示子窗未补登记合成链(D7)。配套的 resize 重建必须保全内容(D6,清透明加左上锚定拷回),否则底边缩放后旧区永久空白。这组契约现在是无 WM 移植的通用检查单。

### 难点二:输入全无响应的假活现场

v18 曾出现"初始界面点击全无响应",画面还在动。定案是事件源唤醒管道读端阻塞:主循环睡在 poll 中被唤醒后,check() 排空管道的最后一次 read 在空管道上永久挂起,而呈现线程独立成帧造成"假活",间歇性自愈路径更具迷惑性。修复是读端补 O_NONBLOCK,并用"心跳插桩二分法"(loop 活、源被轮询、dispatch 进入三层逐级确认)定位。这一轮沉淀的方法论是:画面正常不等于进程健康。

### 难点三:线程边界与悬垂指针

GTK 对象只能在 GTK 线程碰。v13 的对话框响应后 SIGSEGV 定案为 napi 线程直调 gdk_window_hide/get_toplevels 与 GTK 线程窗口销毁竞速,修复是一切窗口级 GDK 调用经 g_idle_add 封回 GTK 线程,输入注入通道随后也统一走 g_main_context_invoke;v19 根治 resize 拖拽 UAF(ensure_surface 销毁后读宽高);v24 用 weak-ref 加强引用组合根治 pointer_toplevel/focus_window 悬挂指针族。这三轮共同确立的纪律是:跨线程只有队列,所有权只有强弱引用两种明确形态。

### 难点四:系统 UI 的避让、沉浸与遮挡

顶部区域在三种设备上表现出不同行为:11.5 的状态栏窗口自带不透明黑底、透明化三路全无效,最终靠藏栏加同色填色条(v34)达成一体;SetContentInset 早于 core 启动会被静默丢弃且永不重发,需要缓存回放(v25);系统键盘避让会整页压缩浮层卡片导致表单出屏与触摸漂移,改 KeyboardAvoidMode.NONE 后由 ArkTS 手动上移并允许负 y。每个结论都来自像素级取证(如顶带 y0-88 恒 (17,17,17) 的实测),而不是日志推断。

### 难点五:沙箱与上游语义的冲突

应用进程 stat 不到 /data/local/tmp(SELinux),import 静默失败以探针 stat=-1 access(R_OK)=-1 定案为文件层问题;导出到 DOWNLOAD 时本 ROM 返回目录型 URI,旧代码取父级导致 EPERM;会话路径必须迁入沙箱并迁移存量配置;系统对浮动子窗底缘有约 40-50px 隐形带吞触摸(D18),工程以 64px 避让垫把按钮抬离底带,双端验证失灵区恢复。上游的容错语义(如 do_import 对不可读路径不报错)也被如实登记,避免误判为移植缺陷。

▍六、编译、安装与启动

构建链为三步脚本加 devecocli,均记载于 PORTING.md 〇.七 节:

bash
cd /Users/andy/DevEcoStudioProjects/AirDaw
bash native/scripts/build_ardour.sh # waf 增量(改 gtk2_ardour/ydk/ytk 树内代码后必须)
bash native/scripts/build_core.sh # 改 airdaw_core 后
source native/scripts/env.sh && bash native/scripts/deploy_daw.sh # 组装 libs+rawfile
devecocli build # HAP
devecocli run --module entry --device <serial> --skip-build # 部署+启动


也可用标准 hvigor 命令构建:

bash
export JAVA_HOME=/Applications/DevEco-Studio.app/Contents/jbr/Contents/Home
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk

hvigorw --mode module -p module=entry assembleHap --no-daemon


连接设备后安装并启动:

bash
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.airdaw.app


部署铁律同样来自真实事故:应用运行中 devecocli run 只走 onNewWant 不换进程,旧进程继续 mmap 旧 .so,新代码永不生效——改 .so 后必须 force-stop 再启动;entry/libs 更新后增量构建可能不重打包,需 rm -rf entry/build 强制全量。诊断日志直读沙箱内 airdaw_core.txt,以 ==== AirDaw core start 标记定位运行轮次。

▍七、当前功能边界

已进入当前可运行产物的能力,依据 PORTING.md 轮次记录与标准审计表:

- 从启动向导(4 页)、启动器、NEW 模板页到编辑器的完整链路,模板列表/描述/选中态真实可用;
- 编辑器 8 组中文菜单、走带、标尺、主控轨,会话打开/保存/导出(Picker 直达)、未命名会话二开保护;
- 混音器/编辑器切页(分档锁帧零半成品)、最大化混音器空间入口、音轨区长按/双击(v45);
- ArkTS 顶栏标签与走带控制、悬浮菜单栏、菜单帽限高(下拉不铺满屏)、对话框子窗与浮层卡片双模式;
- IME 输入与退格、键盘避让、悬停光标链(I-beam/手型)、68 项内置动作脚本与管理器;
- 顶部沉浸(藏栏定案)、暗黑主题(Ardour 原生 dark)、约 90 条起步的汉化体系与 CRC32 指纹机制;
- 双端(平板 + 2in1 PC)回归矩阵与三设备部署经验,SigSEGV 取证与 faultlog 干净记录。

尚未覆盖或登记在册的边界:音频后端当前为 dummy,录音、回放与混音监听不可用,OHAudio 后端是依赖矩阵中标记未完成的规划项;标准审计表中手写笔深度适配、三源捏合缩放、文件夹持久化授权、剪贴板、碰一碰/分享与性能达标线均未实施或未验证;「垂直布局扰动渲染缺失」族按 v19 定案归档为应用层部件级状态缺陷待续查;「最近」页恒空、编辑菜单末项半显(视口裁切)与级联菜单大幅快滑误关等轻微项在册;clearlooks 引擎不可部署为已登记的平台限制。

因此,当前版本更准确的定位是"Ardour 在鸿蒙上的全交互工程预览版":从安装启动到会话编辑的整条 UI 与输入链路真实贯通并有逐轮取证,而音频通路与深度系统适配是下一个阶段的主体。

▍八、总结

AirDaw 证明了一件事:即便像 Ardour 这样深度绑定 X11 生态的 GTK2 大型应用,也可以通过一套自研 GDK 后端加双层宿主在鸿蒙上获得完整的交互生命。它的贡献不在某个单点功能,而在 D6-D24 这份踩坑记录——无窗口管理器环境的渲染契约、输入语义的 X11 等价物、线程与所有权纪律、系统栏避让的像素级取证方法,这些结论对任何想把 GTK 老应用带到鸿蒙的团队都是直接可查的施工手册。

后续工作的重心按文档登记明确排列:实现 OHAudio 音频后端打通真实录音回放(M3 里程碑),逐项补齐标准审计表中 S4-S10 与 S13 的缺口,收掉在册的轻微渲染遗留,并在三台形态各异的设备上维持双端回归矩阵。对一个 DAW 而言,声音通路打通之日,才是这次移植真正验收之时。
楼主 8 天前
想参与讨论?登录 或 30 秒注册。