Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions .cursor/plans/v0.2_ui迭代规划_abf59389.plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
name: v0.2 UI迭代规划
overview: 围绕 `todo.md` 的 v0.2.0 条目,优先完成高观感可视化与 UI 升级,同时为后续扩展更多音频面板预留可扩展接口(不在本迭代落地用户配置文件)。
todos:
- id: frame-contract
content: 扩展 VisualFrame 数据契约并在 AppController frame_provider 注入新增指标
status: completed
- id: ui-panelization
content: 将 TuiRenderer 重构为面板化布局并移除固定行号鼠标映射耦合
status: completed
- id: visual-upgrades
content: 实现频谱峰值保持/衰减与波形双模式显示,并新增至少两类音频信息面板
status: completed
- id: theme-v1
content: 实现内置主题系统与运行时切换,预留配置接口不落地文件解析
status: completed
- id: qa-doc-sync
content: 补齐测试并完成构建测试、双语文档与 changelog 同步
status: completed
isProject: false
---

# v0.2.0 可视化与 UI 综合迭代计划

## 目标与边界

- 目标:在一次迭代内显著提升频谱/波形的观感与可读性,并引入“可扩展面板框架”以支持更多音频信息可视化。
- 你已确认的范围:
- 尽量丰富可视化类型与面板(`full_explore`)。
- 主题系统先做可扩展接口与内置能力,用户配置文件后置(`decide_later`)。
- 非目标:不实现用户主题配置文件解析;不展开长期 CUDA/Rust 方向。

## 现状基线(将复用的代码)

- UI 与交互主入口在 [`/home/virtualguard/vg101/dev/vocalplayer/src/ui/tui_renderer.cpp`](/home/virtualguard/vg101/dev/vocalplayer/src/ui/tui_renderer.cpp) 与 [`/home/virtualguard/vg101/dev/vocalplayer/src/ui/tui_renderer.hpp`](/home/virtualguard/vg101/dev/vocalplayer/src/ui/tui_renderer.hpp)。
- 可视化数据快照由 [`/home/virtualguard/vg101/dev/vocalplayer/src/shared/types.hpp`](/home/virtualguard/vg101/dev/vocalplayer/src/shared/types.hpp) 的 `VisualFrame` 承载。
- 数据生成与注入由 [`/home/virtualguard/vg101/dev/vocalplayer/src/app/app_controller.cpp`](/home/virtualguard/vg101/dev/vocalplayer/src/app/app_controller.cpp) 的 `frame_provider` 完成。
- 频谱/波形算法在 [`/home/virtualguard/vg101/dev/vocalplayer/src/analysis/spectrum_analyzer.cpp`](/home/virtualguard/vg101/dev/vocalplayer/src/analysis/spectrum_analyzer.cpp)。

## 方案总览(先稳接口,再做重视觉)

```mermaid
flowchart LR
audioEngine[AudioEngineWindow] --> analyzerLayer[SpectrumAndMetricAnalyzer]
analyzerLayer --> visualFrame[VisualFrameExtended]
visualFrame --> tuiRenderer[TuiRendererPanels]
tuiRenderer --> uiIntent[UiIntent]
uiIntent --> appController[AppControllerState]
```

- 先扩展 `VisualFrame` 的“数据契约”,再重构 `TuiRenderer` 为面板化渲染,最后叠加主题与动画。
- 保持 `UiIntent -> AppController` 的控制链不变,避免交互回归。

## 实施阶段

### 阶段 A:数据契约扩展(低风险)

- 在 `VisualFrame` 增加可选/默认字段,用于承载新增可视化数据:
- 电平类:`rms_level`、`peak_level`。
- 频段类:`band_energy`(如低/中/高三段)。
- 视图控制类:`visual_mode`(后续面板切换状态)。
- 在 `AppController` 的 `frame_provider` 中填充新字段,先用轻量算法(基于现有 mono window 的 O(n) 统计)。
- 保持所有新字段“缺省可渲染”,保证旧布局兼容。

### 阶段 B:TUI 面板化与布局升级(核心价值)

- 在 `TuiRenderer` 中将当前单体 `vbox` 拆为稳定区块:
- 顶栏(曲目状态/时间/进度)。
- 主可视化区(频谱 + 波形 + 新音频信息面板)。
- 播放列表区(含状态提示)。
- 底栏(快捷键与当前模式)。
- 去除与鼠标映射强耦合的固定行常量(如 `kPlaylistStartY`),改为基于组件结构的相对命中策略,避免后续加行导致点击偏移。
- 新增显示模式切换(例如 `Overview` / `SpectrumFocus` / `WaveFocus` / `Meters`),先用键盘切换并显示当前模式。

### 阶段 C:可视化效果升级(观感提升)

- 频谱:加入峰值保持(peak hold)与平滑衰减;可选对数分桶(至少保留一个模式)。
- 波形:提供“原始波形 + 包络(RMS/平滑)”两种显示态。
- 音频信息面板:至少接入 2 类新指标(建议 RMS 与 peak),并提供统一标尺显示。

### 阶段 D:主题系统 v1(不含用户文件)

- 引入 `Theme` 数据结构与内置主题枚举(如 `Default` / `Neon` / `Mono`)。
- 渲染逻辑只通过 `Theme` 取色,不在组件内写死颜色。
- 增加运行时切换主题的交互入口(键位或模式内切换),并在状态栏可见当前主题名。
- 预留配置扩展点:仅定义 `LoadThemeFromConfig` 接口占位,不实现文件解析。

### 阶段 E:质量门禁与文档同步

- 测试补充:
- `analysis`:新增 RMS/peak/band 计算单测。
- `ui`:关键纯函数(如模式切换、可视化映射)可测试部分补单测。
- 工程验证:`clang-format`、CMake 构建、`ctest` 全量通过。
- 文档同步:更新中英文 README、架构文档与 `changelog.md` 的 `Changed/Added`。

## 交付拆分(建议 PR/提交粒度)

- 切片 1:`VisualFrame` 扩展 + `AppController` 数据注入。
- 切片 2:`TuiRenderer` 面板化重构(保持旧功能等价)。
- 切片 3:新增指标与可视化效果。
- 切片 4:主题系统 v1 与交互入口。
- 切片 5:测试、文档、回归修复。

## 验收标准

- 功能:频谱/波形视觉增强可见;至少 2 个新增音频信息可视化项可稳定显示。
- 交互:现有键位行为不回退;新增模式/主题切换行为清晰可控。
- 稳定性:播放/切歌/暂停场景无明显闪烁、错位或崩溃。
- 性能:默认刷新下交互流畅,无显著卡顿;CPU 占用相较基线可接受。
- 文档:`README.md`、`README_zh-CN.md`、`docs/dev/architecture.md`、`docs/dev/architecture_zh-CN.md`、`changelog.md` 同步更新。
4 changes: 3 additions & 1 deletion .cursor/rules/general.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: VocalPlayer iteration standards (first-cycle learnings)
alwaysApply: true
---

# VocalPlayer General Rules
# vocalplayer General Rules

## 1) Requirements and Planning

Expand All @@ -13,6 +13,8 @@ alwaysApply: true
mode before implementation.
- For UI interaction work, define an intent layer (`UiIntent`) before wiring
rendering and control logic to avoid tight coupling.
- When iterating, focus on iteration plans instead of overly focusing on longterm / debatable plans, unless they are beneficial
to the current iteration plan to be executed.

## 2) Implementation Order (Recommended)

Expand Down
88 changes: 47 additions & 41 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 3.20)

project(
VocalPlayer
VERSION 0.1.1
LANGUAGES C CXX)
VocalPlayer
VERSION 0.2.0
LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand All @@ -19,27 +19,27 @@ set(KISSFFT_TEST OFF CACHE BOOL "" FORCE)
set(KISSFFT_TOOLS OFF CACHE BOOL "" FORCE)

FetchContent_Declare(
miniaudio
GIT_REPOSITORY https://github.com/mackron/miniaudio.git
GIT_TAG 0.11.23)
miniaudio
GIT_REPOSITORY https://github.com/mackron/miniaudio.git
GIT_TAG 0.11.23)
FetchContent_MakeAvailable(miniaudio)

FetchContent_Declare(
kissfft
GIT_REPOSITORY https://github.com/mborgerding/kissfft.git
GIT_TAG 131.1.0)
kissfft
GIT_REPOSITORY https://github.com/mborgerding/kissfft.git
GIT_TAG 131.1.0)
FetchContent_MakeAvailable(kissfft)

FetchContent_Declare(
ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/FTXUI.git
GIT_TAG v5.0.0)
ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/FTXUI.git
GIT_TAG v5.0.0)
FetchContent_MakeAvailable(ftxui)

add_library(
kissfft_lib
STATIC
${kissfft_SOURCE_DIR}/kiss_fft.c)
kissfft_lib
STATIC
${kissfft_SOURCE_DIR}/kiss_fft.c)
target_include_directories(kissfft_lib PUBLIC ${kissfft_SOURCE_DIR})

find_package(PkgConfig QUIET)
Expand All @@ -48,29 +48,29 @@ if(PkgConfig_FOUND)
endif()

add_library(
vocalplayer_core
src/app/app_controller.cpp
src/app/playlist.cpp
src/audio/audio_engine.cpp
src/audio/decoder.cpp
src/audio/metadata.cpp
src/analysis/spectrum_analyzer.cpp
src/ui/tui_renderer.cpp)
vocalplayer_core
src/app/app_controller.cpp
src/app/playlist.cpp
src/audio/audio_engine.cpp
src/audio/decoder.cpp
src/audio/metadata.cpp
src/analysis/spectrum_analyzer.cpp
src/ui/tui_renderer.cpp)

target_include_directories(
vocalplayer_core
PUBLIC
${PROJECT_SOURCE_DIR}/src
${miniaudio_SOURCE_DIR}
${kissfft_SOURCE_DIR})
vocalplayer_core
PUBLIC
${PROJECT_SOURCE_DIR}/src
${miniaudio_SOURCE_DIR}
${kissfft_SOURCE_DIR})

target_link_libraries(
vocalplayer_core
PUBLIC
kissfft_lib
ftxui::screen
ftxui::dom
ftxui::component)
vocalplayer_core
PUBLIC
kissfft_lib
ftxui::screen
ftxui::dom
ftxui::component)

if(TAGLIB_FOUND)
target_compile_definitions(vocalplayer_core PUBLIC VOCALPLAYER_HAS_TAGLIB=1)
Expand All @@ -83,15 +83,16 @@ target_link_libraries(vocalplayer PRIVATE vocalplayer_core)
if(VOCALPLAYER_BUILD_TESTS)
set(BUILD_TESTING ON CACHE BOOL "" FORCE)
enable_testing()

add_executable(
test_spectrum_analyzer
tests/test_spectrum_analyzer.cpp
src/analysis/spectrum_analyzer.cpp)
test_spectrum_analyzer
tests/test_spectrum_analyzer.cpp
src/analysis/spectrum_analyzer.cpp)
target_include_directories(
test_spectrum_analyzer
PRIVATE
${PROJECT_SOURCE_DIR}/src
${kissfft_SOURCE_DIR})
test_spectrum_analyzer
PRIVATE
${PROJECT_SOURCE_DIR}/src
${kissfft_SOURCE_DIR})
target_link_libraries(test_spectrum_analyzer PRIVATE kissfft_lib)
add_test(NAME spectrum_analyzer_test COMMAND test_spectrum_analyzer)

Expand All @@ -102,4 +103,9 @@ if(VOCALPLAYER_BUILD_TESTS)
add_executable(test_keybindings tests/test_keybindings.cpp)
target_include_directories(test_keybindings PRIVATE ${PROJECT_SOURCE_DIR}/src)
add_test(NAME keybindings_test COMMAND test_keybindings)

add_executable(test_theme tests/test_theme.cpp)
target_include_directories(test_theme PRIVATE ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(test_theme PRIVATE ftxui::screen)
add_test(NAME theme_test COMMAND test_theme)
endif()
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@ English | [简体中文](README_zh-CN.md)

A creative C++ CLI music player with real-time rhythm visualization in the terminal.

<video src="assets/vocalplayer.webm" controls width="100%"></video>

</div>

vocalplayer is a creative CLI music player built with C++, focused on
real-time rhythm visualization in terminal environments.
vocalplayer is a creative CLI music player built with C++, focused on real-time rhythm visualization in terminal environments.

## Features

- Local audio playback (`wav` and formats supported by the miniaudio decoder).
- Directory scan + simple playlist sorted by name.
- Real-time spectrum bars and waveform rendering in TUI mode.
- Real-time spectrum bars with peak-hold markers and dual waveform modes.
- Additional audio meters (RMS, Peak, and low/mid/high band energy).
- Track metadata display (`title`, `artist`, and duration; TagLib optional).
- Vim-style playlist interaction (`h/l/j/k`) and Enter-to-play confirmation.
- Panel layout mode switching (`Overview/Spectrum/Waveform/Meters`) and
runtime built-in theme cycling.

## Usage

Expand All @@ -37,6 +41,9 @@ Press `q` in the TUI to quit the current session.
- `Space`: pause/resume current track
- `j`: move playlist selection down
- `k`: move playlist selection up
- `m`: cycle visualization layout mode
- `v`: toggle waveform style (`Raw` / `Envelope`)
- `t`: cycle built-in theme (`Default` / `Miku` / `Teto`)
- Mouse wheel: scroll playlist viewport
- Left click on a playlist item: select that track only
- `Enter`: play the currently selected track
Expand Down
12 changes: 9 additions & 3 deletions README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@

基于C++的创意型CLI音乐播放器,在终端中实现实时节奏可视化。

<video src="assets/vocalplayer.webm" controls width="100%"></video>

</div>

vocalplayer 是一个使用 C++ 构建的创意型 CLI 音乐播放器,重点在于
终端中的实时节奏可视化。
vocalplayer 是一个使用 C++ 构建的创意型 CLI 音乐播放器,重点在于终端中的实时节奏可视化。

## 特性

- 本地音频播放(`wav` 及 miniaudio 解码器支持的格式)。
- 目录扫描 + 简单的按名称排序播放列表。
- TUI 实时频谱柱与波形渲染。
- TUI 实时频谱柱(含峰值保持)与双模式波形渲染。
- 增加音频信息仪表(RMS、Peak、低/中/高频段能量)。
- 曲目信息展示(`title`、`artist`、时长;TagLib 可选)。
- 支持 Vim 风格播放列表交互(`h/l/j/k`)与回车确认切歌。
- 支持可视化布局模式切换与内置主题运行时切换。

## 运行

Expand All @@ -37,6 +40,9 @@ vocalplayer 是一个使用 C++ 构建的创意型 CLI 音乐播放器,重点
- `Space`:暂停/恢复当前曲目
- `j`:播放列表选中下移
- `k`:播放列表选中上移
- `m`:循环切换可视化布局模式
- `v`:切换波形样式(`Raw` / `Envelope`)
- `t`:循环切换内置主题(`Default` / `Miku` / `Teto`)
- 鼠标滚轮:滚动播放列表视窗
- 鼠标左键点击列表项:仅选中该曲目
- `Enter`:播放当前选中曲目
Expand Down
Binary file added assets/vocalplayer.webm
Binary file not shown.
31 changes: 30 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
# Changelog

本文件用于记录 VocalPlayer 的迭代历史,格式参考
本文件用于记录 vocalplayer 的迭代历史,格式参考
[Keep a Changelog](https://keepachangelog.com/)。

## [0.2.0] - 2026-05-12

### Added
- 新增可视化扩展数据契约:
- `VisualFrame` 增加频谱峰值保持、包络波形、`rms_level`、`peak_level`、`band_energies` 与 `visual_mode` 字段。
- 新增分析能力:
- `SpectrumAnalyzer::ComputeWaveformEnvelope()`
- `SpectrumAnalyzer::ComputeLevels()`
- `SpectrumAnalyzer::ComputeBandEnergies()`
- 新增内置主题系统:
- `src/ui/theme.hpp` 定义 `ThemeId`、`Theme`、`GetBuiltinTheme()`、`NextThemeId()`。
- 预留 `LoadThemeFromConfig()` 接口(暂不实现配置文件解析)。
- 新增主题测试:`tests/test_theme.cpp`(并接入 `theme_test`)。

### Changed
- `TuiRenderer` 重构为面板化布局:顶栏、主可视化区、播放列表区、底栏。
- 频谱渲染增加峰值保持标记;波形支持 `Raw/Envelope` 双模式切换。
- 增加音频仪表展示:RMS、Peak、低中高频段能量。
- 增加运行时交互键位:
- `m`:切换可视化布局模式
- `v`:切换波形样式
- `t`:切换内置主题
- 播放列表鼠标命中逻辑从固定行号偏移改为基于渲染区域 `Box` 反射定位,降低布局改动带来的点击偏移风险。
- `CMakeLists.txt` 重新格式化并补齐 `test_theme` 链接依赖(`ftxui::screen`)。

### Docs
- 同步更新 `README.md` 与 `README_zh-CN.md`,补充新增可视化、主题和交互说明。
- 同步更新 `docs/dev/architecture.md` 与 `docs/dev/architecture_zh-CN.md`,反映新的数据契约、分析接口与 UI 架构。

## [0.1.1] - 2026-05-10

### Added
Expand Down
8 changes: 8 additions & 0 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,11 @@ git push --tags
```

It builds, tests, and publishes artifacts for Linux, macOS, and Windows.

### Release Process

1. Develop and document in `dev` branch, update `changelog.md` and project metadata, and submit PR.
2. Maintainer merges PR to `main`, CI automatically runs `clang-tidy` + Linux build/test pipeline.
3. Switch to `main` branch locally, and execute `git pull` to fetch latest code.
4. Execute `git tag -a v*.*.*` to create a new version tag.
5. Execute `git push --tags` to push the tag to the remote repository, which triggers the GitHub Actions release workflow, building and uploading Linux/macOS/Windows triple-platform artifacts.
Loading
Loading