尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Flipper Zero 上的《时之笛》陶笛:flipperzero-ocarina 按键玩法与源码实现全解析

Flipper Zero 上的《时之笛》陶笛:flipperzero-ocarina 按键玩法与源码实现全解析 Flipper Zero 上的《时之笛》陶笛flipperzero-ocarina 按键玩法与源码实现全解析【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipperflipperzero-ocarina 是运行在 Flipper Zero 上的一把“《时之笛》陶笛”它复刻了 N64 经典游戏《塞尔达传说时之笛》中主角 Link 吹奏陶笛Ocarina的核心玩法通过方向键和确认键组合在 Flipper Zero 内置蜂鸣器上吹奏出旋律。本文以仓库中的 关联文档 为骨架结合 ocarina.c 与 application.fam 的完整源码讲解按键映射、音高设计、事件循环与扬声器驱动原理并给出构建安装与吹奏实战指南。1. 项目是什么Flipper Zero 版《时之笛》陶笛原 README 对项目的定位只有一句话A basic Ocarina (of Time) for the Flipper Zero。翻译过来就是一把运行在 Flipper Zero 上的基础版《时之笛》陶笛。它属于该仓库 Applications/Official/source-OLDER 目录下 kyhwana 整理归档的应用源码之一。从 application.fam 可以看到它被归类为fap_categoryMusic音乐类是一个通过 Flipper 应用包FAP机制分发的外部应用apptypeFlipperAppType.EXTERNAL。也就是说它不烧录进固件而是编译成.fap文件拷贝到 SD 卡从 Flipper Zero 的应用菜单中启动。它不依赖键盘矩阵或外部硬件只使用 Flipper Zero 机身自带的压电蜂鸣器speaker发声配合 GUI 服务requires[gui]在 128×64 单色屏幕上绘制简单界面是一个极简但五脏俱全的嵌入式 GUI 音频应用示例。2. 按键映射与 N64 版完全一致的操作逻辑README 明确指出Controls are the same as the N64 version of the Ocarina of Time, the Ok button takes the place of the A button——操作方式与 N64 版《时之笛》完全相同只是用OK 键代替了 N64 手柄上的A 键。对应到 ocarina.c 的switch(event.key)分支完整映射如下Flipper Zero 按键N64 对应触发音符频率 (Hz)音名近似上 (Up)C-UpNOTE_UP587.33D5左 (Left)C-LeftNOTE_LEFT493.88B4右 (Right)C-RightNOTE_RIGHT440.00A4下 (Down)C-DownNOTE_DOWN349.23F4OK (Ok)A 键NOTE_OK293.66D4返回 (Back)—退出应用——在游戏原作中玩家正是通过 C 键方向键与 A 键的组合吹奏不同音高例如“时之笛”主题曲的经典起手式就是 C-Left、C-Right、C-Up。这个 Flipper 版本完整保留了这一交互设计让熟悉原作的玩家可以无缝上手。屏幕界面见draw_callbackocarina.c会用canvas_draw_str显示标题 Ocarina 和提示文字 OK button for A并绘制一个 128×64 的全屏边框canvas_draw_frame(canvas, 0, 0, 128, 64)提示玩家 OK 键等价于 A 键。3. 音高设计五颗按键拼出的音阶五个按键对应的频率在源码开头以宏定义#define NOTE_UP 587.33f // 上D5 #define NOTE_LEFT 493.88f // 左B4 #define NOTE_RIGHT 440.00f// 右A4 #define NOTE_DOWN 349.23 // 下F4 #define NOTE_OK 293.66f // OKD4从乐理上看这五个音D4、F4、A4、B4、D5恰好覆盖了一个以 D 为根音的小调色彩音阶集合——其中 D4–F4–A4 构成 D 小三和弦B4 与 D5 则向上延伸。这意味着OKD4作为低音主音相当于旋律的“根音起点”上D5与下F4构成五度/三度呼应可以吹出常见的旋律骨架原版游戏中最著名的“时之笛”主题曲Zeldas Lullaby以及“Epona 之歌”“Sarias Song”等曲目其动机基本都能落在这几个音高附近因此用这把“5 键陶笛”即可还原许多经典旋律片段。音量方面源码固定为float volume 1.0f满音量由furi_hal_speaker_start(freq, volume)传入见 ocarina.c。4. 源码级剖析一个完整的 Flipper 事件驱动应用虽然 README 只有两行但 ocarina.c 是一个结构完整的 Flipper Zero 应用范例其骨架分配 → 事件循环 → 释放可以作为任何简单 GUI 应用的模板。4.1 应用结构体与初始化typedef struct { FuriMutex* model_mutex; FuriMessageQueue* event_queue; ViewPort* view_port; Gui* gui; } Ocarina;ocarina_alloc()依次完成四件事ocarina.c互斥锁furi_mutex_alloc(FuriMutexTypeNormal)保护共享数据供绘制回调与主循环并发访问时加锁消息队列furi_message_queue_alloc(8, sizeof(InputEvent))容量 8 条的输入事件队列作为 GUI 线程与主循环之间的生产者-消费者通道ViewPortview_port_alloc()注册绘制回调draw_callback与输入回调input_callbackGUI 服务furi_record_open(gui)打开 GUI 系统服务再通过gui_add_view_port(..., GuiLayerFullscreen)把 ViewPort 挂到全屏图层。4.2 输入回调事件进入队列void input_callback(InputEvent* input, void* ctx) { Ocarina* ocarina ctx; furi_message_queue_put(ocarina-event_queue, input, FuriWaitForever); }输入回调在 GUI 线程上下文中执行职责非常单一把按键事件原样放入消息队列FuriWaitForever表示若队列满则阻塞等待不在此处直接驱动硬件从而避免在中断/回调上下文中做耗时操作——这是 Flipper 应用开发的标准做法。4.3 主循环读队列、发音、刷屏ocarina_app()是整个应用的入口同时也是application.fam中声明的entry_point它运行一个事件循环ocarina.cfor(bool processing true; processing;) { FuriStatus status furi_message_queue_get(ocarina-event_queue, event, 100); furi_check(furi_mutex_acquire(ocarina-model_mutex, FuriWaitForever) FuriStatusOk); ... furi_mutex_release(ocarina-model_mutex); view_port_update(ocarina-view_port); }关键行为furi_message_queue_get(..., 100)以100 tick 超时轮询队列没有输入时循环也能周期性醒来并刷新屏幕只有event.type InputTypePress按下瞬间才启动音符InputTypeRelease松开时调用furi_hal_speaker_stop()停止发声ocarina.c。按住不放会持续发声松开即止这与真实吹奏陶笛的“持续音-断音”控制一致InputKeyBack返回键将processing置为false退出循环随后调用ocarina_free()释放资源。4.4 发声原理furi_hal_speaker声音输出使用 Flipper HAL 的furi_hal_speaker_start(frequency, volume)/furi_hal_speaker_stop()。该接口直接驱动机身内置压电蜂鸣器以指定的频率Hz产生方波音调。这是 Flipper Zero 最简的音频输出路径——不需要外接扬声器代码也不依赖任何音频缓冲队列。需要留意一个细节本仓库中同一应用的三个归档版本对扬声器资源的管理有差异kyhwana 版本文关联文档对应版本ocarina.c直接调用furi_hal_speaker_start并在释放时无条件furi_hal_speaker_stop()xMasterX 版ocarina.c则引入了furi_hal_speaker_acquire(1000)/furi_hal_speaker_is_mine()/furi_hal_speaker_release()的资源占用检查确保蜂鸣器未被其他应用占用时才发声退出时也只在确认“扬声器归我所有”后才释放。后者的写法在共享外设speaker 可被闹钟、通知等多处使用的场景下更安全可以作为编写更健壮音频应用的参考——这也侧面说明在 Flipper 固件迭代中外设资源管理经历了从“裸用”到“acquire/release 所有权模型”的演进。4.5 资源释放ocarina_free()ocarina.c按与分配相反的顺序清理禁用并移除 ViewPort → 关闭 gui record → 释放 ViewPort → 释放消息队列 → 释放互斥锁 → 停止蜂鸣器 →free结构体。这套“对称分配/释放”的写法避免了资源泄漏是嵌入式应用的生命周期管理范本。5. 构建与安装从源码到 SD 卡应用清单 application.fam 完整声明了构建所需信息App( appidOcarina, nameOcarina, apptypeFlipperAppType.EXTERNAL, entry_pointocarina_app, cdefines[APP_OCARINA], requires[gui], stack_size1 * 1024, order30, fap_iconicons/music_10px.png, fap_categoryMusic, fap_icon_assetsicons, )apptypeFlipperAppType.EXTERNAL编译为独立 FAP 应用.fap而非固件内置entry_pointocarina_app启动入口对应 ocarina.c 中的int32_t ocarina_app(void* p)requires[gui]声明依赖 GUI 服务构建系统会据此链接对应模块stack_size1 * 1024应用线程栈仅 1 KB说明该应用占用资源极低fap_iconicons/music_10px.png菜单图标取自 icons/music_10px.png10×10 像素的音乐符号位图fap_categoryMusic应用在菜单中归类到“Music音乐”分组。部署路径基于 Flipper Zero 通用 FAP 流程以当前仓库为源准备 Flipper Zero 官方固件 SDK 与fbt构建工具链将 kyhwana/ocarina 目录作为外部应用接入构建或直接纳入applications外部应用目录执行fbt fap_ocarina或通过fbt的 FAP 构建目标生成ocarina.fap将生成的.fap拷贝到 SD 卡的apps/Music/目录图标资源一并放入在 Flipper Zero 上进入Apps → Music选择 Ocarina 启动。说明上述构建命令以 Flipper Zero 官方fbt工具链为准具体目标名以所用固件版本的构建系统输出为准本仓库仅提供应用源码与清单不包含固件工程。6. 实战玩法如何用它吹出旋律把 README 的按键说明转化为实际演奏方法单音吹奏按下对应方向键或 OK即发声松开即停。短促点按可形成断音staccato长按则得到持续音连续旋律用“按下-松开-按下-松开”的节奏依次触发不同音符。例如用 OKD4→ 上D5→ 右A4的走向即可构成类似《塞尔达摇篮曲》开头的上行动机熟悉原作的玩家可以直接套用 N64 版的曲目按键谱如 Zeldas Lullaby、Eponas Song、Sarias Song 的经典 C 键序列退出按返回键Back结束应用蜂鸣器自动停止见ocarina_free中的furi_hal_speaker_stop()。得益于按键映射与原版一致、五个音高经过挑选这把“口袋陶笛”既能用来复刻经典曲目也可以自由即兴。7. 延伸阅读仓库内的其他实现与相关资源同款应用的其他归档版本参见 grnch/ocarina 与 xMasterX/ocarina其中 xMasterX 版补充了furi_hal_speaker_acquire资源保护适合对照学习外设所有权管理同类furi_hal_speaker用法仓库中 tuning_fork.c、dtmf_dolphin_hal.c、music_beeper_worker.c 等同样是基于 HAL 蜂鸣器发声的应用可对比不同音源驱动的写法若想进一步了解 Flipper Zero 的音频/音乐能力可浏览仓库的 Music_Player 目录RTTTL 曲库与主题曲资源作为曲目来源参考。总结flipperzero-ocarina 用不到 120 行 C 代码在 Flipper Zero 上实现了一把致敬《塞尔达传说时之笛》的 5 键陶笛。它既是 N64 经典操作的“口袋复刻”也是一个结构清晰、可以直接学习的 Flipper Zero 事件驱动应用范例——从消息队列、ViewPort 回调、互斥锁到furi_hal_speaker方波发声覆盖了嵌入式 GUI 音频应用的完整链路。读者既可以按上文流程构建安装把它当成随身的小乐器把玩也可以借这份源码掌握 Flipper Zero 外部应用开发的核心套路。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表