mcu_hi3321_watch/tjd/ui/app/player/LyricParser.cpp
2025-05-26 20:15:20 +08:00

171 lines
4.3 KiB
C++

#include "LyricParser.h"
#include "sys_config.h"
#include <fstream>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <vector>
#define ENABLE_PRINT_INFO 1
#define ENABLE_DEBUG 1
#if ENABLE_PRINT_INFO
#define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制
#define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开
#define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开
#if ENABLE_DEBUG
#define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) // 调试信息打印一般常开
#else
#define static_print_debug(...)
#endif
#else
#define static_print_info(...)
#define static_print_warn(...)
#define static_print_error(...)
#endif
// clang-format off
static const std::string MetaData[7][2] = {
{"ti", "title"},
{"al", "album"},
{"ar", "artist"},
{"au", "author"},
{"by", "creator"},
{"re", "encoder"},
{"ve", "encoder_version"}
};
// clang-format on
bool LrcParser::parseLrc(const std::string &lrcFile)
{
currentIndex_ = 0;
lrcData_.clear();
lyrics_.clear();
std::ifstream fin;
fin.open(lrcFile, std::ios_base::in);
if (!fin.is_open()) {
static_print_error("LRC Can't open file %s", lrcFile.c_str());
return false;
}
std::stringstream buffer;
buffer << fin.rdbuf();
lrcData_ = buffer.str();
fin.close();
if (lrcData_.empty()) {
static_print_error("LRC file is empty");
return false;
}
// 先读取头部
size_t index = parseHeader();
if (index == lrcData_.length()) {
static_print_error("No lyrics_ text");
return false;
}
lrcData_.erase(0, index);
std::string line = readLine();
while (!line.empty()) {
parseLine(line);
line = readLine();
}
duration_ = (--lyrics_.end())->first;
readIndex_ = lyrics_.begin();
return true;
}
LyricPacket LrcParser::readPacket()
{
LyricPacket packet;
if (readIndex_ != lyrics_.end()) {
packet.pts = readIndex_->first;
packet.lyric = readIndex_->second;
readIndex_++;
}
return packet;
}
bool LrcParser::seek(int64_t timestamp)
{
auto end = --lyrics_.end();
for (readIndex_ = lyrics_.begin(); readIndex_ != end; readIndex_++) {
if (readIndex_->first > timestamp) {
if (readIndex_ != lyrics_.begin()) {
readIndex_--;
}
return true;
}
}
return false;
}
int64_t LrcParser::duration() const { return duration_; }
size_t LrcParser::parseHeader()
{
size_t offset = 0;
size_t length = lrcData_.length();
if (offset >= length)
return offset;
while (offset < length) {
std::string meta, data;
if (lrcData_.at(offset) == '[') {
while (++offset < length && lrcData_.at(offset) != ':') {
if (lrcData_.at(offset) >= 'a' && lrcData_.at(offset) <= 'z')
meta += lrcData_.at(offset);
else
return offset - 1;
}
while (++offset < length && lrcData_.at(offset) != ']') {
data += lrcData_.at(offset);
}
}
offset++;
}
return offset;
}
void LrcParser::parseLine(const std::string &line)
{
std::regex pattern("\\[(\\d+):(\\d+).(\\d+)\\](.*)");
std::smatch matches;
if (std::regex_search(line, matches, pattern)) {
int64_t minute = std::stoi(matches[1].str()) * 60 * 1000;
int64_t second = std::stoi(matches[2].str()) * 1000;
int64_t millisecond =
matches[3].str().length() == 3 ? std::stoi(matches[3].str()) : std::stoi(matches[3].str()) * 10;
int64_t pts = minute + second + millisecond;
std::string data = matches[4].str();
lyrics_[pts] = data;
}
}
std::string LrcParser::readLine()
{
size_t length = lrcData_.length();
std::string line;
while (currentIndex_ < length) {
if (lrcData_.at(currentIndex_) == '\n') {
currentIndex_++;
break;
} else {
line += lrcData_.at(currentIndex_);
currentIndex_++;
}
}
return line;
}