# Ubuntu LCD 多媒体终端
**Repository Path**: YOUNGQI-LYQ/ubuntu-lcd-multimedia-terminal
## Basic Information
- **Project Name**: Ubuntu LCD 多媒体终端
- **Description**: 一个简易的实训项目。
- **Primary Language**: C/C++
- **License**: GPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-07-06
- **Last Updated**: 2025-07-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 多媒体终端
本项目是一个基于 C/C++ 混合编程,运行于 x86/Ubuntu 环境下的多功能 LCD 屏幕应用。通过直接操作 Linux Framebuffer 和 Input Event 设备,它实现了一个集电子相册(支持缩放/平移)、电子书阅读器(支持TTS语音朗读)、电子琴(支持录音/回放)于一体的交互式多媒体系统,旨在模拟嵌入式设备的底层开发方式。
## 视频演示
[点击观看视频](https://imgcdn.youngqi.cn/res/video.mp4)
## 目录
- [项目特色](#项目特色)
- [技术栈](#技术栈)
- [项目架构图](#项目架构图)
- [执行流程图](#执行流程图)
- [核心逻辑剖析](#核心逻辑剖析)
- [Framebuffer 图形渲染](#Framebuffer 图形渲染)
- [触摸/输入事件处理](#触摸/输入事件处理)
- [语音合成 (TTS) 集成](#语音合成 (TTS) 集成)
- [电子琴录音与回放](#电子琴录音与回放)
- [应用模块化管理](#应用模块化管理)
- [环境部署 (x86/Ubuntu)](#环境部署 (x86/Ubuntu))
- [编译与运行](#编译与运行)
- [使用介绍](#使用介绍)
- [文件结构](#文件结构)
## 项目特色
- **底层驱动模拟**: 直接通过 `mmap` 内存映射操作 Framebuffer (`/dev/ubuntu_lcd`),通过 `read` 读取输入事件 (`/dev/ubuntu_event`),模拟了嵌入式 Linux 开发中对硬件的底层访问方式。
- **功能复合型应用**: 清晰地分为三大核心模块:
- **电子相册**: 支持 `.jpg`/`.bmp` 图片浏览,并实现了**图片缩放与平移**功能。
- **电子书**: 支持 `txt` 文本阅读,并集成了科大讯飞SDK,实现了**TTS语音朗读**功能。
- **电子琴**: 12键模拟钢琴,不仅能弹奏,还支持**实时录音与旋律回放**。
- **动态UI与状态保存**:
- 主菜单界面包含**实时时钟**和**相册图片轮播**,提升了界面的动态感。
- 电子书模块能够**自动保存阅读进度**,方便用户下次继续阅读。
- **C/C++ 混合编程**: 主体框架使用 C 语言,同时通过 C++ 桥接文件 (`tts_bridge.cpp`) 封装和调用科大讯飞的 C++ SDK,是混合编程的典型实践。
- **资源整合**: 整合了 `libjpeg` 库、`mpg123` 命令行工具、`iconv` 编码转换库以及 `HZK16`/`ASC16` 点阵字库,构建了功能完善的多媒体支持体系。
## 技术栈
- **编程语言**: `C` / `C++` (用于桥接TTS SDK)
- **操作系统**: `Linux` (在 `Ubuntu` 下开发和测试)
- **核心 API**:
- `Linux Framebuffer`: 用于图形用户界面的直接渲染。
- `Linux Input Event Subsystem`: 用于接收和解析触摸屏或鼠标的输入事件。
- `POSIX API`: `mmap`, `select`, `open`, `read`, `iconv`, `system` 等。
- **图形与图像**:
- `libjpeg`: 用于解码 `JPG` 格式的图片。
- 自定义 `BMP` 解析器与渲染器,支持缩放和平移。
- **音频处理**:
- **播放**: `mpg123` 作为外部命令行工具,用于播放 `MP3` 音频文件。
- **语音合成**: `科大讯飞 SparkChain TTS SDK` 用于将文本转换为语音。
- **字体与编码**:
- 点阵字库 (`HZK16`, `ASC16`): 用于在中英文界面上显示文本。
- `iconv`: 用于 `GB2312` 到 `UTF-8` 的文本编码转换,以适配TTS SDK的要求。
- **构建系统**: `GNU Make`
## 项目架构图
```mermaid
graph TD
subgraph "应用层 (Application Layer)"
A[主程序入口
main.c]
end
subgraph "功能模块 (Feature Modules)"
B["电子相册
run_photo_album()"]
C["电子书
run_ebook()"]
D["电子琴
run_piano()"]
end
subgraph "服务/逻辑层 (Service/Logic Layer)"
E["UI 绘制服务
show_main_menu(), etc."]
F["图片列表管理
photo.c (双向链表)"]
G["MP3 播放服务
mp3.c"]
TTS_Bridge["TTS C++桥接层
tts_bridge.cpp"]
end
subgraph "驱动/库/SDK层 (Driver, Library & SDK Layer)"
H["LCD 驱动封装
lcd.c (Framebuffer)"]
I["触摸驱动封装
ts.c (Input Event)"]
J["libjpeg 解码库"]
K["字体库 (HZK16, ASC16)"]
L["mpg123 命令行工具"]
SDK["讯飞 TTS SDK (.so)"]
ICONV["iconv 编码转换库"]
end
A --> B
A --> C
A --> D
A --> E
B --> F; B --> J; B --> H; B --> I
C --> K; C --> H; C --> I; C --> TTS_Bridge; C --> ICONV
D --> G; D --> H; D --> I
G --> L
TTS_Bridge --> SDK
```
## 执行流程图
```mermaid
flowchart TD
Start[开始] --> Init{"1. 初始化
打开 Framebuffer, Input Device
内存映射(mmap)
初始化TTS SDK"};
Init --> Loop["2. 主循环 (while)"];
Loop --> DrawMenu["2.1 绘制/更新主菜单
show_main_menu()"];
DrawMenu --> CheckUpdates{"2.2 定时任务
(非阻塞等待)
- 更新时钟
- 轮播相册预览"};
CheckUpdates --> CheckInput{"2.3 检查触摸输入
select() / get_touch_event()"};
CheckInput -- "无输入" --> Loop;
CheckInput -- "有输入" --> ProcessInput;
ProcessInput --> Choice{"2.4 根据坐标判断用户选择"};
Choice -- "相册区域" --> RunPhoto["执行 run_photo_album()
(进入相册子循环)"];
Choice -- "电子书区域" --> RunEbook["执行 run_ebook()
(进入电子书子循环)"];
Choice -- "电子琴区域" --> RunPiano["执行 run_piano()
(进入电子琴子循环)"];
Choice -- "退出区域" --> Cleanup{"3. 清理资源
清屏, munmap, close(fd)
反初始化TTS SDK"};
RunPhoto --> Loop;
RunEbook --> Loop;
RunPiano --> Loop;
Cleanup --> End[结束];
```
## 核心逻辑剖析
### Framebuffer 图形渲染
所有图形界面的绘制都通过直接操作 Framebuffer 完成,核心函数封装在 `lcd.c` 中。关键逻辑是:通过 `mmap` 将设备物理显存映射到进程的虚拟地址空间,后续所有绘图操作(画点、画矩形、渲染文字/图片)都简化为对这块内存的直接读写。本项目还实现了带缩放和平移的图像绘制函数 (`draw_jpeg_with_scale`),通过计算缩放后像素与原图像素的映射关系,实现高质量的图像显示。
### 触摸/输入事件处理
输入处理逻辑封装在 `ts.c` 中。`get_touch_event` 函数通过 `read` 读取 `struct input_event`,并设计了一个小型状态机:它等待一个 `EV_ABS` 类型的 X 坐标事件,然后等待一个 Y 坐标事件,两者都收到后才认为是一次有效的触摸,并返回坐标。这种方式不依赖 `EV_SYN` 同步信号,增强了对不同输入设备的兼容性。主循环则使用 `select` 实现对触摸事件的非阻塞监听,允许在等待用户操作的同时执行其他任务(如更新时钟)。
### 语音合成 (TTS) 集成
这是电子书模块的一大亮点,实现了 C 与 C++ SDK 的协同工作:
1. **获取文本**: 当用户点击“听书”按钮,程序首先从当前页的文本内容中提取字符串(GB2312编码)。
2. **编码转换**: 由于讯飞SDK要求UTF-8编码,程序调用 `iconv` 库函数,将提取的 GB2312 字符串转换为 UTF-8 格式。
3. **调用C++桥接层**: C代码(`main.c`)调用 `tts_bridge.cpp`中通过 `extern "C"` 暴露的 `text_to_speech_c` 函数。
4. **SDK交互**: `tts_bridge.cpp` 内的C++代码负责调用讯飞 SparkChain C++ SDK,发起语音合成请求,并将合成的音频流(MP3格式)写入本地文件 (`./res/audio/tts_output.mp3`)。
5. **播放音频**: 合成成功后,主程序通过 `system()` 命令调用 `mpg123` 在后台播放该音频文件。
### 电子琴录音与回放
电子琴模块通过一个精巧的状态机 (`P_IDLE`, `P_RECORDING`, `P_PLAYBACK`) 和数据结构 `struct NoteEvent` 实现录音与回放功能。
- **录音**: 当进入 `P_RECORDING` 状态,每次按下琴键,程序会记录两样东西:被按下的**琴键索引** (`key_index`) 和距离上一次按键的**时间间隔**(`delay_us`,通过高精度时钟 `get_time_in_us()` 获取)。这些信息被存入 `recorded_song` 数组中。
- **回放**: 当进入 `P_PLAYBACK` 状态,程序会遍历 `recorded_song` 数组。对于每个音符,它会先等待 `delay_us` 微秒,然后播放对应 `key_index` 的音效,从而精准复现原始弹奏的节奏和音高。
### 应用模块化管理
`main.c` 充当顶层调度器。`main` 函数的主循环负责绘制主菜单并等待用户输入。获取触摸坐标后,通过 `if-else` 判断坐标区域,调用相应的功能模块函数(如 `run_photo_album()`)。每个功能模块是一个独立的子循环,处理该模块内的所有交互,直到用户点击“返回”,函数返回,控制权交还给 `main` 函数,再次显示主菜单。
## 环境部署 (x86/Ubuntu)
1. **安装基础依赖**
```bash
sudo apt-get update
sudo apt-get install build-essential libjpeg-dev mpg123
```
- `build-essential`: 提供 `gcc`, `g++` 和 `make`。
- `libjpeg-dev`: 用于解码 JPG 图片。
- `mpg123`: 用于播放 MP3 音频。
2. **配置讯飞TTS SDK**
本项目需要科大讯飞的Linux版SparkChain SDK。
- 前往讯飞开放平台下载SDK。
- 将解压后的 `libs` 和 `include` 文件夹内容,放入您项目的一个指定目录,例如 `sdk/`。Makefile需要正确配置头文件和库文件的搜索路径。
3. **配置模拟设备节点 (如果需要)**
代码中使用了 `/dev/ubuntu_lcd` 和 `/dev/ubuntu_event` 作为设备路径。您需要创建符号链接将其指向 x86 平台对应的真实设备。
- **Framebuffer**:
```bash
# 将 /dev/ubuntu_lcd 链接到 /dev/fb0
sudo ln -s /dev/fb0 /dev/ubuntu_lcd
```
- **Input Event**:
```bash
# 首先用 `cat /proc/bus/input/devices` 找到你的鼠标设备号 (eventX)
# 然后将 /dev/ubuntu_event 链接到该设备
sudo ln -s /dev/input/eventX /dev/ubuntu_event
```
## 编译与运行
1. **配置 Makefile**
确保 `Makefile` 中的编译和链接选项正确:
- `CC` 应设为 `gcc`,`CXX` 设为 `g++`。
- `INCLUDE_PATH` 应包含 `-I./inc -I./sdk/include`。
- `LDFLAGS` 应包含 `-L./sdk/libs -lSparkChain -ljpeg` 等链接选项。
2. **编译**
在项目根目录下执行:
```bash
make
```
该命令会分别编译 C 和 C++ 源文件,并最终链接成一个名为 `main` 的可执行文件。
3. **运行**
确保终端位于项目根目录,然后以超级用户权限运行(因为需要访问设备文件):
```bash
sudo ./main
```
## 使用介绍
程序启动后,会显示主菜单。所有操作均通过鼠标点击(模拟触摸)完成。
- **主菜单**
- **电子相册**: 点击进入。
- **电子书**: 点击进入。
- **电子琴**: 点击进入。
- **右下角“退出”按钮**: 退出程序。
- **电子相册模块**
- **右侧控制栏**: `上一张`/`下一张`, `放大`/`缩小`, `上`/`下`/`左`/`右`平移, `返回`。
- **电子书模块**
- **右侧控制栏**: `上`/`下`翻页, `上`/`下`换章, **`听书 (TTS)`**, `返回`。
- **电子琴模块**
- **琴键区域**: 点击播放对应音效。
- **底部控制栏**: `录制`, `停止录制`, `播放录音`, `返回`。
## 文件结构
```
MULTIMEDIA_TERMINAL/
├── inc/ # 头文件目录 (.h)
│ ├── lcd.h # LCD 驱动封装
│ ├── mp3.h # MP3 播放功能封装
│ ├── photo.h # 电子相册模块 (链表结构)
│ ├── read.h # 电子书模块
│ ├── ts.h # 触摸驱动封装
│ ├── tts_bridge.h # C++桥接层头文件
│ ├── ASC16.h # ASCII 字体数据
│ └── HZK16.h # 汉字字体数据
├── res/ # 资源文件目录
│ ├── audio/ # 存放MP3文件 (琴键音效, TTS输出)
│ ├── imagefiles/ # 存放图片文件 (UI元素, 相册图片)
│ ├── novel/ # 存放TXT格式的电子书文本
│ └── state/ # 存放程序状态文件 (如 ebook_state.txt)
├── src/ # 源文件目录
│ ├── main.c # 主程序入口与模块调度
│ ├── lcd.c # LCD 驱动实现
│ ├── mp3.c # MP3 播放功能实现
│ ├── photo.c # 电子相册功能实现 (链表操作)
│ ├── read.c # 电子书功能实现 (文本渲染)
│ ├── ts.c # 触摸驱动实现
│ └── tts_bridge.cpp # TTS 功能的 C++ 桥接实现
├── sdk/ # (需手动创建) 存放第三方SDK
│ ├── include/ # 存放SDK头文件
│ └── libs/ # 存放SDK库文件 (.so)
├── .gitignore # Git 忽略文件配置
├── Makefile # 编译脚本
└── main # (编译后生成) 最终可执行文件
```