QSound、QSoundEffect播放WAV音频

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,挖个坑,我在后面的文章里,结合一个局域网实时语音通话的例子,来进行介绍。

猜你喜欢

转载自blog.csdn.net/qq_44723937/article/details/126045981