QSound、QSoundEffect播放WAV音频

本文旨在介绍QSound、QSoundEffect的简单播放音频的方法以及对这两个类的一些基本介绍

最近,接受了一个同事写的代码,发现在播放音乐的地方,会有内存泄露,代码如下:

if (type == "HELLO") {
QSound *sound = new QSound("./radio/hello.wav");
sound->play(); // 执行其他操作
}

这里明显会出现内存泄露,但是如果使用局部变量的话,就会在这个if结束之后销毁掉,那有可能音乐没有播放完就停了的结果。

QSound

因为是第一次接触这个类,秉着不懂的就学的原则,所以我转头去看了帮助文档。

简介&使用方法

QSound类提供了一种播放**.wav格式音乐的方法。

你可以使用
QSound**类的静态函数来播放音乐,之前的代码就可以写成下面这样:

QSound::play("./radio/hello.wav");

但是这种方法只会播放一次,没有办法循环播放。你也可以实例化对象,来设置播放的循环次数。

基本函数

  1. fileName()

    这个函数,用于获取设置的资源文件的文件名。

    QString fileName() const;
  2. loops()

    获取音频循环的次数

    int loops() const;
  3. setLoops()

    设置循环的次数

    void setLoops(int number);
  4. loopsRemaining()

    返回音频剩余的循环次数,如果返回的是QSound::Infinite代表循环播放

    int loosRemaining() const;
  5. isFinished()

    判断当前音频是否播放完成。

    bool isFinished() const;
  6. play()与stop()

    play()和stop()函数分别代表开始和结束当前音频的播放。

    void play();
    void stop();

      但是在使用这个类的时候,我有点困惑,都找不到一个信号用于标志音频播放结束了,那怎么去判断是否结束播放,进而释放资源呢?
    然后在文档中找到了一句话:
      大致的意思就是,如果你想要更多对播放的音频的控制,请去看QSoundEffectQAudioOutput这两个类。下面介绍一下这两个类。

QSoundEffect

简介&基本使用

这个类是用于低延迟的播放未经过压缩的音频(比如WAV文件)。这个类的比较常见的应用就是播放一个提示音;
基本的使用方法如下:

QSoundEffect *soundEffect = new QSoundEffect();
// 设置声音源文件的路径
soundEffect->setSource(QUrl::fromLoaclFile("./radio/hello.wav"));
// 音频循环的次数
soundEffect->setLoopCount(1);
// 音量
soundEffect->setVolume(1);
soundEffect->play(); // 连接信号,当播放完毕时,自动销毁对象。
connect(soundEffect, &QSoundEffect::playingChanged, [soundEffect] () {
if (effect->isPlaying()) {
effect->deleteLater();
}
});

  使用这个类,就可以连接信号playingChanged,来实现在音乐播放完之后自动销毁。

属性及对应的函数

这个类拥有的属性有:

  1. category(种类):QString

      这个属性包含当前QSoundEffect的种类,不同的平台,可以根据不同的category来设置执行不同的音频通道或者允许用户设置不同的音量等级。这个应该类似于Windows下的音量合成器
    设置、读取函数和值发生改变时发射的信号分别为:

    // 读取属性函数
    QString category() const // 设置属性函数
    void setCategory(const QString &category); // 属性改变时发射的信号
    void categoryChanged();
  2. loops(循环次数):int

      这个属性保存了音频的循环次数,当这个的值为0或者1时,音频都只会播放一次。当这个属性的值为QSoundEffect::Infinite为无限循环
      这个属性,可以在音频正在播放的时候进行修改,修改其实就是改变remaining loops的值。
    设置、读取函数和值发生改变时发射的信号分别为:

    // 读取属性函数
    int loopCount() const // 设置属性函数
    void setLoopCount(int loops); // 属性改变时发射的信号
    void loopCountChanged();
  3. loopsRemaining(剩余循环次数):const int

    当前音频剩余的播放次数。
    读取的函数和发生改变时发射的信号为:

    // 读取属性函数
    int loopsRemaining() const; // 属性改变时发射的信号
    void loopsRemainingChanged();
  4. muted(静音):bool

    这个属性提供了一种控制静音的方法。
    设置、读取以及发生改变时发射的信号为:

    // 读取属性函数
    bool isMuted() const; // 设置属性函数
    void setMuted(int loops); // 属性改变时发射的信号
    void mutedChanged();
  5. playing(播放状态):bool

    这个属性标识了当前音频是不是处于播放状态。
    对应的函数为:

    // 读取属性函数
    bool isPlaying() const; // 属性改变时发射的信号
    void playingChanged();
  6. source(资源文件):QUrl

    这个属性保存了声音文件的url。如果想要加载资源文件,这个URL必须存在,并且应用必须有访问指定目录的权限。
    对应的函数为:

    // 读取属性函数
    QUrl source() const; // 设置属性函数
    void setSource(const QUrl &url); // 属性改变时发射的信号
    void sourceChanged();
  7. status(状态): const Status

    这个属性指示了当前QSoundEffect的状态。
    对应的函数为:

    // 读取属性函数
    QSoundEffect::Status status() const; // 属性改变时发射的信号
    void statusChanged();
  8. volume(音量):qreal

    这个属性保存了当前播放的音量,范围是[0.0,1.0]。
    对应的函数为:

    // 读取属性函数
    qreal volume() const; // 设置属性函数
    void setVolume(qreal volume); // 属性改变时发射的信号
    void volumeChanged();

源码探秘

再次回到QSound这个类,由于在帮助文档里对QSound::play这个函数的介绍里,没有说会不会导致内存泄漏,同时也没有一个信号来标识音频播放完成。但是如果使用一个局部变量,在变量销毁时,音频就会停止播放,就会导致问题,于是,带着这些问题,我去看了QSound的源码。
首先,关于play这个静态函数的定义:

void QSound::play(const QString &filename)
{
// Object destruction is generally handled via deleteOnComplete
// Unexpected cases will be handled via parenting of QSound objects to qApp
QSound *sound = new QSound(filename, qApp);
sound->connect(sound->m_soundEffect, &QSoundEffect::playingChanged,
sound, &QSound::deleteOnComplete);
sound->play();
}

发现,它连接了一个槽函数,那就是deleteOnComplte

/*!
\internal
*/
void QSound::deleteOnComplete()
{
if (!m_soundEffect->isPlaying())
deleteLater();
}

  在这里,就可以得出一个结论,play这个静态函数可以放心用,他会在播放结束之后,自动释放。
  QSound其实也是在QSoundEffect上封装了一层,播放音频还是用的QSoundEffect,后面,在看了QSoundEffect之后,发现其底层用的是QAudioOutput,关于QAudioOutput和QAudioInput,挖个坑,我在后面的文章里,结合一个局域网实时语音通话的例子,来进行介绍。

QSound、QSoundEffect播放WAV音频的更多相关文章

  1. 用 Qt 的 QAudioOutput 类播放 WAV 音频文件

    用 Qt 的 QAudioOutput 类播放 WAV 音频文件 最近有一个项目,需要同时控制 4 个声卡播放不同的声音,声音文件很简单就是没有任何压缩的 wav 文件. 如果只是播放 wav 文件, ...

  2. 使用WaveOut API播放WAV音频文件(解决卡顿)

    虽然waveout已经过时,但是其api简单,有些时候也还是需要用到. 其实还是自己上msdn查阅相应api最靠谱,waveout也有提供暂停.设置音量等接口的,这里给个链接,需要的可以自己查找: h ...

  3. S3C2416裸机开发系列19_Fatfs播放录像wav音频文件

    S3C2416裸机开发系列19 Fatfs播放录像wav音频文件 国际象棋男孩    1048272975 多媒体资源,一般都是以文件的形式存储在固化存储器中.Fatfs所支持的fat32为windo ...

  4. 多浏览器播放wav格式的音频文件

    html5的audio标签只在火狐下支持wav格式的音频播放,无法兼容IE和google , 使用audioplayer.js 基本上能支持大部分浏览器播放wav音频文件,经测试IE.火狐.googl ...

  5. Windows Phone 8初学者开发—第21部分:永久保存Wav音频文件

    原文 Windows Phone 8初学者开发—第21部分:永久保存Wav音频文件 第21部分:永久保存Wav音频文件 原文地址:http://channel9.msdn.com/Series/Win ...

  6. Windows Phone 8初学者开发—第20部分:录制Wav音频文件

    原文 Windows Phone 8初学者开发—第20部分:录制Wav音频文件 原文地址:http://channel9.msdn.com/Series/Windows-Phone-8-Develop ...

  7. 1.1.6-学习Opencv与MFC混合编程之---播放WAV音乐和 alpha融合功能

    源代码:http://download.csdn.net/detail/nuptboyzhb/3961698 Alpha融合菜单项 1.      增加alpha融合菜单项,修改相应的属性,建立类向导 ...

  8. C语言解析WAV音频文件

    C语言解析WAV音频文件 代码地址: Github : https://github.com/CasterWx/c-wave-master 目录 前言 了解WAV音频文件 什么是二进制文件 WAV的二 ...

  9. C++播放wav音乐和音效

    1.  #include <mmsystem.h>#pragma comment(lib,"winmm.lib")PlaySound(TEXT("c:\\te ...

  10. 8086汇编语言 调用声卡播放wav文件(sound blaster)

    开更 大概最后做了一个能播放无损音乐(无压缩.不需解码)的播放器 原理是基于dosbox的模拟声卡,通过硬件之间的相互通讯做到的 关于详细内容接下来再讲. 一.从dosbox入手 我们知道cpu可以直 ...

随机推荐

  1. 使用 IntelliJ IDEA 构建 Spring Framework 5.3.21 源码问题解决

    源码版本 1.下载地址:https://github.com/spring-projects/spring-framework/tags 2.选择要构建的源码版本并下载,例如:5.3.21 相关环境 ...

  2. mybatis-plus多表联合分页查询

    1.entity层要写个Vo实体类 2.controller @AutoLog(value = "员工CURD-分页列表查询")@ApiOperation(value=" ...

  3. Qt编写视频监控系统79-四种界面导航栏的设计

    一.前言 最初视频监控系统按照二级菜单的设计思路,顶部标题栏一级菜单,左侧对应二级菜单,最初采用图片在上面,文字在下面的按钮方式展示,随着功能的增加,二级菜单越来越多,如果都是这个图文上下排列的按钮, ...

  4. React 应用的 Nginx 缓存控制

    典型 React 应用面临的缓存问题,可通过 Nginx 配置进行解决 通用部署 构建应用后,只需使用 Nginx 指向静态文件即可 server { listen 80; root /PATH/TO ...

  5. 老生常谈——分布式限流:部分Sentinal源码解读

    基础知识 HTTP CODE = 429 "请求过多" A. 限流的类型 服务端 客户端 限流的标的 IP 用户 ... 基本要求 准确限制过量的请求. 低延时.限流器不能拖慢HT ...

  6. 重温Go语法笔记 | 函数

    函数 返回值带有变量名 return时可以不写返回值,在返回值位置声明即可 func namedRetvalue() (a, b int) { a = 1 b = 2 return } 匿名函数 定义 ...

  7. Linux 压缩命令集合

    01. tar格式 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!) 02. gz格式 解压1:gunzi ...

  8. java基础知识回顾之java Thread类学习(三)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

    1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以 ...

  9. G1原理—7.G1的GC日志分析解读

    大纲 1.TLAB的GC日志解读 2.YGC的GC日志解读 3.模拟YGC(单次GC及多次GC的不同场景) 4.打开实验选项查看YGC的详情日志信息 5.Mixed GC日志信息之初始标记过程 6.M ...

  10. Superset 用户集成完整方案(iframe方式)

    本次集成方案经过个人测试,根据前面2个集成方案的资料,撰写,相关说明由于个人知识水平有限不一定理解准确,有错误的地方环境评论区评论: 1.用户集成方式: A系统用户,通过A的某个界面,iframe嵌入 ...