QT 音乐播放器【二】 歌词同步+滚动+特效

news2024/11/25 16:54:59

文章目录

      • 效果图
      • 概述
      • 代码
        • 解析歌词
        • 歌词同步
        • 歌词特效
      • 总结

效果图

在这里插入图片描述


概述

  • 先整体说明一下这个效果的实现,你所看到的歌词都是QGraphicsObject,在QGraphicsView上绘制(paint)出来的。也就是说每一句歌词都是一个图元(item)
  1. 为什么用QGraphicsView框架?

    • 在做歌词滚动效果时,我看网上实现这一效果基本上都是用QLabel,这样或许简单很多,但是效果单一,且不够灵活。使用图形视图这套,图形项可以自由地被移动、缩放、旋转和编辑。当然主要还是为了提升自己,可以更熟悉这套框架。
  2. 如何解析歌词?

    • 这里解析的是lrc文件为一般的歌词文件,格式如下:格式是固定的,那么就可以通过正则表达式来解析。然后存放在一个QMap中,key是时间,value是歌词。
    [02:08.496]乌蒙山连着山外山
    [02:11.138]月光洒下了响水滩
    [02:13.993]有没有人能告诉我
    [02:16.487]可是苍天对你在呼唤
    
  3. 如何同步歌词?

    • QMediaPlayer中有一个信号positionChanged,播放音乐时会时刻刻触发,可以获取当前播放时间。然后和前面我们存放在QMap中的时间进行对比,所以QMap存放的时间格式要按positionChanged发出的时间格式来解析。但我试验过很多次俩者的时间都是无法精确相等的。这里采取的方案是遍历QMap,找到第一个时间大于等于positionChanged发出的时间,然后获取这个时间对应的歌词,这便是当前的歌词。然后通过当前的key在获取前后几句的歌词。
  4. 歌词滚动以及那些特效如何实现的?

    • 同步歌词的时候会获取当前歌词以及前后几句歌词,提前存好对应歌词的特效,如下:这里面存了一个QMap,里面存放了每一句歌词的属性,包括字体大小,位置,透明度等等。
     m_textMapInfolst << QMap<QString, QString>{
    {"index", "1"},
    {"font", "12"},
    {"y", "-100"},
    {"x", "300"},
    {"opacity", "0.2"}};
    

    我这里有七句歌词,那么就存七个QMap在一个QList中,当歌词刷新的时候就去遍历,根据QMap中的属性来设置item歌词,这里的图元要自己实现,重写paint函数。


代码

解析歌词
  • 解析的时候把格式设置GB 2312,不然会是乱码。按行已经QMediaPlayer的时间格式读取数据,并全部存放到listLyricsMap中。
bool Lyrics::readLyricsFile(QString lyricsPath)
{
    listLyricsMap.clear();
    QFile file(lyricsPath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        listLyricsMap.clear();
        return false;
    }
    QTextStream in(&file);
    in.setCodec("GB 2312");
    QString line;
    while (!in.atEnd())
    {
        line = in.readLine();
        analysisLyricsFile(line);
    }

    return true;
}

bool Lyrics::analysisLyricsFile(QString line)
{
    if (line == NULL || line.isEmpty())
    {
        return false;
    }
    QRegExp timeRegExp("\\[(\\d+):(\\d+\\.\\d+)\\]");

    if (timeRegExp.indexIn(line) != -1)
    {
        qint64 totalTime = timeRegExp.cap(1).toInt() * 60000 + // 分钟
                           timeRegExp.cap(2).toFloat() * 1000; // 秒

        QString lyricText = line.mid(timeRegExp.matchedLength());
        listLyricsMap.insert(totalTime, lyricText);
    }
    return true;
}
歌词同步
  • 绑定信号
    connect(player, SIGNAL(positionChanged(qint64)),
            this, SLOT(updateTextTime(qint64)));
  • 读取对应listLyricsMap中的歌词

void MainWindow::updateTextTime(qint64 position)
{
    auto lrcMap = lyric->getListLyricsMap();
    qint64 previousTime = 0;
    qint64 currentLyricTime = 0;
    QMapIterator<qint64, QString> i(lrcMap);
    while (i.hasNext())
    {
        i.next();
        if (position < i.key())
        {
            QString currentLyric = lrcMap.value(previousTime);
            currentLyricTime = previousTime;
            break;
        }
        previousTime = i.key();
    }

    QStringList displayLyrics; // 存储将要显示的歌词列表。
    // 获取将要显示的歌词
    QMap<qint64, QString>::iterator it = lrcMap.find(currentLyricTime);
    // 显示前三句,如果it不是开头,就向前移动迭代器
    for (int i = 0; i < 3 && it != lrcMap.begin(); i++)
    {
        --it;
        displayLyrics.prepend(it.value());
    }

    // 重置迭代器
    it = lrcMap.find(currentLyricTime);
    QString currntStr = QString();
    // 显示当前句
    if (it != lrcMap.end())
    {
        currntStr = QString("<font color='red'>" + it.value() + "</font>");
        displayLyrics.append(it.value());
    }

    // 显示后三句
    for (int i = 0; i < 3 && it != lrcMap.end(); i++)
    {
        ++it;
        if (it != lrcMap.end())
        {
            displayLyrics.append(it.value());
        }
    }
    //更新显示
    imageViewWindow->textChanged(displayLyrics);
}
歌词特效
  • 同步于上述歌词的改动,清空场景遍历特效m_textMapInfolst,重新进行图元绘制
void ImageViewWindow::textChanged(QStringList &lsit)
{
 m_scene->clear();
 for (int index = 0; index < m_textMapInfolst.size(); index++)
 {
  const auto textInfoMap = m_textMapInfolst[index];
  GraphicsText *item = new GraphicsText();
  item->setStr(lsit[index]);
  item->setStrFont(textInfoMap["font"].toInt());
  item->setItemOffset(QPointF(textInfoMap["x"].toInt() + image_xoffset, textInfoMap["y"].toInt() + image_yoffset));
  item->setZValue(textInfoMap["index"].toInt());
  item->setOpacity(textInfoMap["opacity"].toFloat());
  m_items << item;
  m_scene->addItem(item);
 }
}
  • 自绘图元
void GraphicsText::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
 painter->setFont(m_font);
 if (m_font.pointSize() > 20)
 {
  painter->setPen(QPen(Qt::red));
 }
 else
 {
  painter->setPen(QPen(Qt::blue));
 }
 painter->drawText(offset, str);
}

总结

  • 实现这个功能遇到的问题挺多的,比如绘制文本的时候只有一根线显示,是要view设置setViewportUpdateMode(QGraphicsView::FullViewportUpdate),类似的问题挺多,还不好找。
  • 歌词特效这块还可以再扩展,字体,入场效果等都可以设置。
  • 当然这个功能还有很多可以优化的地方,BUG或许也不少,实现标题的功能的逻辑就是如上,可以作为参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1803653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT中为程序加入超级管理员权限

QT中为程序加入超级管理员权限 Chapter1 QT中为程序加入超级管理员权限1. mingw编译器2. MSVC编译器3. CMAKE Chapter2 如何给QT程序添加管理员权限(UAC)的几种方法1、Qt Creator中方案一&#xff1a;&#xff08;仅适用于使用msvc编译器&#xff09;方案二&#xff1a;&#x…

【NI国产替代】产线测试:数字万用表(DMM),功率分析仪,支持定制

数字万用表&#xff08;DMM&#xff09; • 6 位数字表显示 • 24 位分辨率 • 5S/s-250KS/s 采样率 • 电源和数字 I/O 均采用隔离抗噪技术 • 电压、电流、电阻、电感、电容的高精度测量 • 二极管/三极管测试 功率分析仪 0.8V-14V 的可调输出电压&#xff0c;最大连…

【NI国产替代】高速数据采集模块,最大采样率为 125 Msps,支持 FPGA 定制化

• 双通道高精度数据采集 • 支持 FPGA 定制化 • 双通道高精度采样率 最大采样率为 125 Msps12 位 ADC 分辨率 最大输入电压为 0.9 V -3 dB 带宽为 30 MHz 支持 FPGA 定制化 根据需求编程实现特定功能和性能通过定制 FPGA 实现硬件加速&#xff0c;提高系统的运算速度FPGA…

【每日刷题】Day59

【每日刷题】Day59 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 1103. 分糖果 II - 力扣&#xff08;LeetCode&#xff09; 2. 1051. 高度检查器 - 力扣&#xff08…

【Vue】Vue路由-重定向

问题 网页打开时&#xff0c; url 默认是 / 路径&#xff0c;未匹配到组件时&#xff0c;会出现空白 解决方案 重定向 → 匹配 / 后, 强制跳转 /home 路径 语法 { path: 匹配路径, redirect: 重定向到的路径 }, 比如&#xff1a; { path:/ ,redirect:/home }代码示例 const…

智慧互联网医院系统的技术架构与实现

随着信息技术的迅猛发展&#xff0c;智慧互联网医院系统成为现代医疗服务的重要组成部分。该系统融合了多种先进技术&#xff0c;旨在提升医疗服务的效率和质量&#xff0c;优化患者体验。本文将深入探讨智慧互联网医院系统的技术架构及其实现方法&#xff0c;并提供相关代码示…

GPT-4o仅排第二!北大港大等6所高校联手,发布权威多模态大模型榜单!

多模态大模型视频分析能力榜单出炉&#xff1a; Gemini 1.5 Pro最强&#xff0c;GPT-4o仅排第二&#xff1f; 曾经红极一时的GPT-4V屈居第三。 3.5研究测试&#xff1a;hujiaoai.cn 4研究测试&#xff1a;askmanyai.cn Claude-3研究测试&#xff1a;hiclaude3.com 最近&#…

数据挖掘--认识数据

数据挖掘--引论 数据挖掘--认识数据 数据挖掘--数据预处理 数据挖掘--数据仓库与联机分析处理 数据挖掘--挖掘频繁模式、关联和相关性&#xff1a;基本概念和方法 数据挖掘--分类 数据挖掘--聚类分析&#xff1a;基本概念和方法 数据对象与属性类型 属性&#xff1a;是一…

接口(API)开发,测试工具-apifox

前言 为什么需要接口&#xff08;API&#xff09;? 因为不同的平台或系统可能使用不同的技术栈、编程语言或数据格式。API提供了一个标准化的方式&#xff0c;使得这些不同的系统可以相互交换数据和功能调用&#xff0c;实现互操作性 在开发日常的项目交互中&#xff0c;不…

【数据可视化系列】使用Python和Seaborn绘制相关性热力图

热力图&#xff08;Heatmap&#xff09;是一种数据可视化工具&#xff0c;它通过使用颜色的深浅来展示数据矩阵中数值的大小或密度。在热力图中&#xff0c;每种颜色的深浅代表数据的一个特定值或值的范围&#xff0c;通常使用红色、黄色和绿色等颜色渐变来表示数据的热度&…

uinty游戏界面模糊的解决方法

1.把低分辨率关掉 2.调缩放&#xff0c;不要调长宽高 3.调整画布的分辨率 4.调整图片的像素点

mqtt-emqx:paho.mqttv5的简单例子

# 安装emqx 请参考【https://blog.csdn.net/chenhz2284/article/details/139551293?spm1001.2014.3001.5502】 # 下面是示例代码 【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</…

前端多人项目开发中,如何保证CSS样式不冲突?

在前端项目开发中&#xff0c;例如突然来了一个大项目&#xff0c;很可能就需要多人一起开发&#xff0c;领导说了&#xff0c;要快&#xff0c;要快&#xff0c;要快&#xff0c;你们给我快。然后下面大伙就一拥而上&#xff0c;干着干着发现&#xff0c;一更新代码&#xff0…

【介绍下什么是Kubernetes编排系统】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

spark-3.5.1+Hadoop 3.4.0+Hive4.0 分布式集群 安装配置

Hadoop安装参考: Hadoop 3.4.0HBase2.5.8ZooKeeper3.8.4Hive4.0Sqoop 分布式高可用集群部署安装 大数据系列二-CSDN博客 一 下载:Downloads | Apache Spark 1 下载Maven – Welcome to Apache Maven # maven安装及配置教程 wget https://dlcdn.apache.org/maven/maven-3/3.8…

[word] word如何清除超链接 #媒体#笔记#知识分享

word如何清除超链接 办公中&#xff0c;少不了使用word&#xff0c;这个是大家必备的软件&#xff0c;今天给大家分享下word如何清除超链接的操作办法&#xff0c;一起来学习下吧&#xff01; 1、清除所有超链接 按下组合键CtrlshiftF9&#xff0c;就可以将网上复制带有超链…

【python】python电影评论数据抓取分析可视化(源码+数据+课程论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

打开C语言常用的内存函数大门(三) —— memset()函数(内含讲解用法和模拟实现)

文章目录 1. 前言2. memset函数2.1 memset函数原型2.2 memset函数参数的介绍2.3 memset函数的使用演示 3. memset函数的模拟实现4. 总结 1. 前言 哈喽&#xff0c;我们又见面了。通过前面两个内存函数(memcpy、memmove函数)讲解的锤炼后&#xff0c;对如何解析一个自己从来没有…

Shell脚本学习_环境变量深入

目录 1.Shell环境变量深入&#xff1a;自定义系统环境变量 2.Shell环境变量深入&#xff1a;加载流程原理介绍 3.Shell环境变量深入&#xff1a;加载流程测试 4.Shell环境变量深入&#xff1a;识别与切换Shell环境类型 1.Shell环境变量深入&#xff1a;自定义系统环境变量 …

在Three.js中实现模型点击高亮:整合EffectComposer与OutlinePass的终极指南

效果【后期实现鼠标点击选中轮廓后给出一个弹窗显示相应的模型信息】 标签指示线参考我的上一篇文章 引言 Three.js不仅让WebGL的3D图形编程变得简单易懂&#xff0c;还通过其强大的扩展库支持丰富的后期处理效果&#xff0c;为3D场景增添无限魅力。本篇文章将引导您深入了…