Qt的音频(QAudioOutput、OpenAL)

Qt音频采集与录制
wav音频图
Qt之QWave音频波形显示控件(有双通道)
Qt-音频编辑 QAudioWave
wav格式介绍
C++实现声音文件的播放(OpenAL、Fmod、BASS、SFML)
6个声音频谱软件
wav音频文件解析读取 定点转浮点分析 幅值提取(C语言实现)
Qt显示WAV音频文件的波形图/频谱图
QtPotPlayer(好)
Qt进阶之路/playerdemo

1、PCM声音格式

(1)频率范围
声音频率在20Hz~20kHz之间的声波。
(2)采样率
在数字音频领域,常用的采样率有:

  • 8000 Hz - 电话所用采样率, 对于人的说话已经足够 11025 Hz - 电话所用采样率
  • 22050 Hz - 无线电广播所用采样率(常用) 32000 Hz - miniDV 数码视频 camcorder、DAT (LP mode)所用采样率
  • 44100 Hz - 音频 CD, 也常用于 MPEG-1 音频(VCD,SVCD,MP3)所用采样率
  • 47250 Hz - 商用 PCM 录音机所用采样率
  • 48000 Hz - miniDV、数字电视、DVD、DAT、电影和专业音频所用的数字声音所用采样率
  • 50000 Hz - 商用数字录音机所用采样率 96000 Hz或者 192000 Hz - DVD-Audio、一些 LPCM DVD 音轨、BD-ROM(蓝光盘)音轨、和 HD-DVD (高清晰度 DVD)音轨所用所用采样率

(3)内存布局:

(4)比特率bps(bit per second)
比特率也叫码率,指音乐每秒播放的数据量,单位用bit表示。

bps = 采样率×采样位宽×声道数

44.1K×16×2 =1411.2Kbps

波形数据传输速率(每秒平均字节数) = 采样频率 × 音频通道数 × 采样位宽 / 8

2、QAudioOutput使用

Qt播放PCM音频(裸流)文件的三种方法 (最开始看的)
QT QAudioOutput+QIODevice 音频流实时播放

//CAudioDevice.h---------------------
#ifndef CAUDIODEVICE_H
#define CAUDIODEVICE_H

#include <QObject>
#include <QIODevice>

class CAudioDevice  :public QIODevice
{
public:
    CAudioDevice(const QByteArray  &pcm, QObject *parent = nullptr);
    ~CAudioDevice();
    qint64 readData(char *data, qint64 maxlen); //重新实现的虚函数
    qint64 writeData(const char *data, qint64 len); //它是个纯虚函数, 不得不实现
private:
    QByteArray m_baPcm;
    int        m_lenWritten;
};

#endif // CAUDIODEVICE_H

//CAudioDevice.cpp-------------------
#include "CAudioDevice.h"
#include <QDebug>
CAudioDevice::CAudioDevice(const QByteArray  &pcm, QObject *parent):QIODevice (parent),m_baPcm(pcm),m_lenWritten(0)
{
    this->open(QIODevice::ReadOnly);
}
CAudioDevice::~CAudioDevice()
{
    this->close();
}
qint64 CAudioDevice::readData(char *data, qint64 maxlen)
{
    if (m_lenWritten >= m_baPcm.size())
    {
        qDebug()<<"m_lenWritten >= m_baPcm.size(), return";
         return 0;
    }
    //计算未播放的数据的长度.
    int len = (m_lenWritten+maxlen) > m_baPcm.size() ? (m_baPcm.size() - m_lenWritten) : maxlen;

    memcpy(data, m_baPcm.data()+m_lenWritten, len); //把要播放的pcm数据存入声卡缓冲区里.
    m_lenWritten += len; //更新已播放的数据长度.
    return len;
}
qint64 CAudioDevice::writeData(const char *data, qint64 len)
{
    return  len;
}
//Widget.h-------------------
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "CAudioDevice.h"
#include <QAudioFormat>
#include <QAudioOutput>
#include <QTimer>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_btnCAudioDevice_clicked();
    void on_btnQAudioOutput_clicked();
    void on_btnOpenAL_clicked();
    void slotTimeout();

private:
    Ui::Widget *ui;
    // for QAudioOutput 
    QByteArray    m_ba;
    QAudioOutput *m_pAudioOutput;
    QIODevice    *m_pDevice;
    QTimer       *m_pTimer;
    bool         m_bFinish;
};
#endif // WIDGET_H

//Widget.cpp---------
#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QDir>
#include <QDebug>


Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget),m_pAudioOutput(nullptr),m_pDevice(nullptr),m_pTimer(nullptr),m_bFinish(true)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btnCAudioDevice_clicked()
{
    //读入文件
    QByteArray ba;
    QFile file(QDir::currentPath()+"/1.wav");
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug()<<"open file error";
        return;
    }
    ba = file.readAll();
    file.close();
    //format
    QAudioFormat fmt;
    fmt.setSampleRate(44100);
    fmt.setChannelCount(2);
    fmt.setSampleSize(16);
    fmt.setCodec("audio/pcm");
    fmt.setCodec("audio/pcm");
    fmt.setByteOrder(QAudioFormat::LittleEndian);
    fmt.setSampleType(QAudioFormat::UnSignedInt);

    //播放
    CAudioDevice *dev = new CAudioDevice(ba);
    QAudioOutput *out = new QAudioOutput(fmt, this);
    out->start(dev);
}
void Widget::on_btnQAudioOutput_clicked()
{

    //读入文件
    //QByteArray ba;
    QFile file(QDir::currentPath()+"/1.wav");
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug()<<"open file error";
        return;
    }
    m_ba = file.readAll();
    file.close();
    //format
    QAudioFormat fmt;
    fmt.setSampleRate(44100);
    fmt.setChannelCount(2);
    fmt.setSampleSize(16);
    fmt.setCodec("audio/pcm");
    fmt.setCodec("audio/pcm");
    fmt.setByteOrder(QAudioFormat::LittleEndian);
    fmt.setSampleType(QAudioFormat::UnSignedInt);

    //音频设备信息.
    QAudioDeviceInfo info = QAudioDeviceInfo::defaultOutputDevice();
    if (!info.isFormatSupported(fmt)) {
        qDebug()<<"default format not supported try to use nearest";
        fmt = info.nearestFormat(fmt);
    }
    if(m_pAudioOutput == nullptr)
        m_pAudioOutput = new QAudioOutput(fmt, this);
    if(m_pDevice == nullptr)
        m_pDevice = m_pAudioOutput->start();
    if(m_pTimer == nullptr)
    {
        m_pTimer=new QTimer(this);
        //connect(m_pTimer, SIGNAL(timeout()), SLOT(slotTimeout()));
        connect(m_pTimer,&QTimer::timeout,this,&Widget::slotTimeout);
    }
    m_pTimer->start(10);
    m_bFinish = false;
//    while (!m_bFinish) {
//        slotTimeout();
//    }



}

void Widget::slotTimeout()
{
    static int i=0;
    if(i<m_ba.size()/1764)
    {
        QByteArray tempBuffer;
        tempBuffer.append(m_ba.data()+i*1764,1764);

        if(m_pAudioOutput&&m_pAudioOutput->state()!=QAudio::StoppedState&&
                m_pAudioOutput->state()!=QAudio::SuspendedState)
        {
            int chunks = m_pAudioOutput->bytesFree()/m_pAudioOutput->periodSize();
            while (chunks)
            {
                if (tempBuffer.length() >= m_pAudioOutput->periodSize())
                {
                    //写入到扬声器.
                    m_pDevice->write(tempBuffer.data(),m_pAudioOutput->periodSize());
                    tempBuffer = tempBuffer.mid(m_pAudioOutput->periodSize());
                }
                else
                {
                    //写入到扬声器.
                    m_pDevice->write(tempBuffer);
                    tempBuffer.clear();
                    break;
                }
                --chunks;
            }
        }
    }
    else {
        m_bFinish=true;
        m_pTimer->stop();
        i=-1;

    }
    i++;
}

void Widget::on_btnOpenAL_clicked()
{

}

今天又碰到了QAudioOutput的天花板

//这是立即播放新数据,停止正在播放的-----
bool PCMPlayer::initData(int nChannels,int SampleRate,int nSampleSize)
{
    if(nullptr != m_audioOut){
        return true;
    }
    QAudioFormat audioFmt;
    audioFmt.setChannelCount(nChannels);
    audioFmt.setCodec("audio/pcm");
    audioFmt.setSampleRate(SampleRate);
    audioFmt.setSampleSize(nSampleSize);
    audioFmt.setByteOrder(QAudioFormat::LittleEndian);
    audioFmt.setSampleType(QAudioFormat::SignedInt);
    m_audioOut = new QAudioOutput(audioFmt);
    /*m_audioOut->setBufferSize(10000000);*/
    connect(m_audioOut,&QAudioOutput::stateChanged,this,[&](QAudio::State state){
        if (QAudio::ActiveState == state)
        {
            m_bFinished = false;//新的一段开始播放,设置未播放完的标识位
        }
        else if(QAudio::IdleState == state)
        {
            if (!m_bFinished)//与QAudio::ActiveState中标识位的false对应
            {
                emit sig_PlayFinished();
            }
        }
    });
     /*m_device = m_audioOut->start();
    if(nullptr == m_device){
        return false;
    }*/ 
    return true;
}
void PCMPlayer::playData(QByteArray data)
{
    m_bFinished = true;
    if(nullptr != m_audioOut)
    {
        m_audioOut->reset();//清空缓存中原来的数据--------
        if(!start())
        {
        	return ;
        }
    }
    if(nullptr != m_device){
        m_device->write(data.toStdString().c_str(), data.length());
    }
}
bool PCMPlayer::start()
{
	if(nullptr == m_audioOut)
	{
		return false;
	}
    m_audioOut->setBufferSize(10000000); //重新设置大小----
    m_device = m_audioOut->start();      //重新启动-------

    if(nullptr == m_device){
        return false;
    }
    return true;
}

3、openAL使用

官方简单例子
OpenAl编程入门:播放一段音频
openal全教程
基于OpenAL的播放封装类(用的)
openal播放裸数据(有遍历设备)
Linux下使用Openal播放声音类
Openal播放音频(win+android)

3.1 查看应用环境所用的声卡驱动

(OSS、ALSA、PulseAudio、PipeWire、Solaris、SndIO)
Windows-only(MMSystem、DSound、WASAPI)
PortAudio、PulseAudio、JACK、CoreAudio、
OpenSL (Android)、 Oboe (Android)、SDL2、Wave Writer、
Linux查看声卡及驱动命令
//查看设备
cat /proc/asound/cards
cat /proc/asound/devices
ll /dev/snd
//如果是alsa
cat /proc/asound/version //alsa版本
$ alsactl -v
$ aplay ./1.wav
在这里插入图片描述

3.2 编译

编译时确保:
For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio were detected (if your target system uses them). For Windows, make sure DirectSound was detected.
使用alsa,要先编译alsa,并在cmakelist中设置目录变量
LINUX编译alsa

//修改cmakelist
set(ALSA_INCLUDE_DIR "/home/mysoft/alsa-lib-1.2.6/install/include")
set(ALSA_LIBRARY  "/home/mysoft/alsa-lib-1.2.6/install/lib")

//编译openal----
BUILD_LIBS=${HOME}/build_libs 
export PATH=${BUILD_LIBS}/bin:${PATH}
export PKG_CONFIG_PATH=${BUILD_LIBS}/lib/pkgconfig:${PKG_CONFIG_PATH} 
rm -rf build
mkdir build
cd build 
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=${BUILD_LIBS} .. 
make
make install

cmake时的输出:(提示需要设置alsa的头文件目录和库目录)

-- The C compiler identification is GNU 9.2.0
-- The CXX compiler identification is GNU 9.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1") 
-- Looking for posix_memalign
-- Looking for posix_memalign - found
-- Performing Test HAVE___RESTRICT
-- Performing Test HAVE___RESTRICT - Success
-- Performing Test HAVE_LIBATOMIC
-- Performing Test HAVE_LIBATOMIC - Success
-- Performing Test HAVE_FNO_MATH_ERRNO
-- Performing Test HAVE_FNO_MATH_ERRNO - Success
-- Performing Test HAVE_GCC_PROTECTED_VISIBILITY
-- Performing Test HAVE_GCC_PROTECTED_VISIBILITY - Success
-- Performing Test HAVE_VISIBILITY_HIDDEN_SWITCH
-- Performing Test HAVE_VISIBILITY_HIDDEN_SWITCH - Success
-- Performing Test HAVE_MSSE2_SWITCH
-- Performing Test HAVE_MSSE2_SWITCH - Success
-- Looking for xmmintrin.h
-- Looking for xmmintrin.h - found
-- Looking for emmintrin.h
-- Looking for emmintrin.h - found
-- Looking for pmmintrin.h
-- Looking for pmmintrin.h - found
-- Looking for smmintrin.h
-- Looking for smmintrin.h - found
-- Looking for arm_neon.h
-- Looking for arm_neon.h - not found
-- Performing Test HAVE_SSE_INTRINSICS
-- Performing Test HAVE_SSE_INTRINSICS - Success
-- Looking for malloc.h
-- Looking for malloc.h - found
-- Looking for cpuid.h
-- Looking for cpuid.h - found
-- Looking for intrin.h
-- Looking for intrin.h - not found
-- Looking for guiddef.h
-- Looking for guiddef.h - not found
-- Looking for initguid.h
-- Looking for initguid.h - not found
-- Looking for pow in m
-- Looking for pow in m - found
-- Looking for clock_gettime in rt
-- Looking for clock_gettime in rt - found
-- Looking for dlfcn.h
-- Looking for dlfcn.h - found
-- Looking for dlopen in dl
-- Looking for dlopen in dl - found
-- Performing Test HAVE_GCC_GET_CPUID
-- Performing Test HAVE_GCC_GET_CPUID - Success
-- Looking for posix_memalign
-- Looking for posix_memalign - found
-- Looking for _aligned_malloc
-- Looking for _aligned_malloc - not found        //--------
-- Looking for proc_pidpath
-- Looking for proc_pidpath - not found           //--------
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test HAVE_PTHREAD
-- Performing Test HAVE_PTHREAD - Success
-- Looking for pthread_setschedparam
-- Looking for pthread_setschedparam - found
-- Looking for include files pthread.h, pthread_np.h
-- Looking for include files pthread.h, pthread_np.h - not found    //--------
-- Looking for pthread_setname_np
-- Looking for pthread_setname_np - not found         //--------
-- Looking for pthread_set_name_np
-- Looking for pthread_set_name_np - not found        //--------
-- Looking for getopt
-- Looking for getopt - found
-- Could NOT find DBus1 (missing: DBus1_INCLUDE_DIRS DBus1_LIBRARIES)     //--------
-- Could NOT find ALSA (missing: ALSA_LIBRARY ALSA_INCLUDE_DIR)        //--------
-- Found OSS: /usr/include/x86_64-linux-gnu                    //--------
-- Checking for module 'libpipewire-0.3'
--   No package 'libpipewire-0.3' found                        //--------
-- Could NOT find AudioIO (missing: AUDIOIO_INCLUDE_DIR)       //--------
-- Could NOT find SoundIO (missing: SOUNDIO_LIBRARY SOUNDIO_INCLUDE_DIR)           //--------
-- Could NOT find PortAudio (missing: PORTAUDIO_LIBRARY PORTAUDIO_INCLUDE_DIR)     //--------
-- Could NOT find PulseAudio (missing: PULSEAUDIO_LIBRARY PULSEAUDIO_INCLUDE_DIR)  //--------
-- Could NOT find JACK (missing: JACK_LIBRARY JACK_INCLUDE_DIR)                    //--------
-- Could NOT find OpenSL (missing: OPENSL_LIBRARY OPENSL_INCLUDE_DIR OPENSL_ANDROID_INCLUDE_DIR)  //-------- 
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Could NOT find SDL2 (missing: SDL2_LIBRARY SDL2_INCLUDE_DIR)      //--------
-- Could NOT find Git (missing: GIT_EXECUTABLE)                      //--------
-- Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR)      //--------
-- Could NOT find MySOFA (missing: MYSOFA_LIBRARY MYSOFA_INCLUDE_DIR ZLIB_FOUND)   //--------
-- Could NOT find SndFile (missing: SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR)           //--------
-- Could NOT find SDL2 (missing: SDL2_LIBRARY SDL2_INCLUDE_DIR)     //--------
-- 
-- Building OpenAL with support for the following backends:
--     OSS, WaveFile, Null                                         //--提示支持的驱动------
-- 
-- Building with support for CPU extensions:
--     Default, SSE, SSE2, SSE3, SSE4.1
-- 
-- Embedding HRTF datasets
-- 
-- Installing library and headers
-- Installing sample configuration
-- Installing HRTF data files
-- Installing AmbDec presets
-- 
-- Building utility programs
-- Building configuration program
-- 
-- Building example programs
-- 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/mysoft/openal-soft-master/build

3、OpenAL常用 函数

//buffer
openal_buffer_create()      // Generate OpenAL buffer
openal_buffer_data()        // Load a buffer with data
openal_buffer_destroy()     // Destroys an OpenAL buffer
openal_buffer_get()       	// Retrieve an OpenAL buffer property
openal_buffer_loadwav() 	// Load a .wav file into a buffer
//context
openal_context_create() 	// Create an audio processing context
openal_context_current()  	// Make the specified context current
openal_context_destroy() 	// Destroys a context
openal_context_process() 	// Process the specified context
openal_context_suspend()  ——— Suspend the specified context
//device
openal_device_close()  ———— Close an OpenAL device
openal_device_open()  ———— Initialize the OpenAL audio layer
//listener
openal_listener_get()  ———— Retrieve a listener property
openal_listener_set()  ———— Set a listener property
//source
openal_source_create()  ——— Generate a source resource
openal_source_destroy()  ——— Destroy a source resource
openal_source_get()  ————— Retrieve an OpenAL source property
openal_source_pause()  ——— Pause the source
openal_source_play()  ———— Start playing the source
openal_source_rewind()  ——— Rewind the source
openal_source_set()  ———— Set source property
openal_source_stop()  ————Stop playing the source
openal_stream()  —————— Begin streaming on a source

4、调用过程:

//查看支持的设备
int checkEnumerationSupport()
{
    ALboolean enumeration;
    enumeration = alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT");
    if (enumeration == AL_FALSE) {
        // enumeration not supported
        std::cout << "enumerating devices NOT supported\n";
    } else {
        // enumeration supported
        std::cout << "enumerating devices supported\n";
    };
    return 0;
}
alutInit(NULL, NULL);
ALuint source1;              //存储source的ID
alGenSources(1, &source1);  //创建一个ALSource,并把其ID存入source1

ALuint buffer1 = alutCreateBufferFromFile("音频文件名.wav");
alSourcei(source1, AL_BUFFER, buffer1);
alSourcePlay(source1);

ALint state;
do{
    alGetSourcei(source1, AL_SOURCE_STATE, &state);
} while (state == AL_PLAYING);

alDeleteSources(1, &source1);
alDeleteBuffers(1, &buffer1);
alutExit();

//打开设备,创建设备
ALCdevice *dev = alcOpenDevice(NULL);
ALCcontextCurrent *cc = alcCreateContext(dev, NULL);
alcMakeContextCurrent(cc);
//创建音源和缓冲器
ALuint bid, sid;
alGenSources(1, &sid);
alGenBuffers(1, &bid);
//取得pcm数据,用缓冲区来关联它
ALvoid *data;
ALsizei size, bits, freq;
ALenum format;
ALboolean loop;
alutLoadWAVFile("boom.wav", &format, &data, &size, &freq, &loop); //alut中的函数,也可自己读进data
alBufferData(bid, format, data, size, freq);     //将数据存入buffer
//用音源关联缓冲器
alSourcei(sid, AL_BUFFER, bid);
//播放音源然后等待直到完成
alSourcePlay(sid);
ALint state;
do{
alGetSourcei(sid, AL_SOURCE_STATE, &state);    //查询状态,直到播完
}while(state == AL_PLAYING);     
//然后释放它
alDeleteSources(1, &sid);
alDeleteBuffers(1, &bid);
alcMakeContextCurrent(NULL);
alcDestroyContext(cc);
alcCloseDevice(dev);

3、音频图

Qt显示wav波形图

QPainter音频图
音频图
音频控件
Qt显示WAV音频文件的波形图/频谱图
H5录音音频可视化-实时波形频谱绘制、频率直方图

波形图的横坐标一般为时间,纵坐标一般为dB (即分贝)来表示;有的时候只关心振幅的趋势,那就对振幅进行归一化为 [-1,1]范围内。

4、语谱图(Spectrogram)

音频相关知识集合
语谱图 Spectrogram 的分类
语谱图(一) Spectrogram 的定义与机理
语谱图(二) Spectrogram 的产生
语谱图(三) Spectrogram 的实例
语谱图(四) Mel spectrogram 梅尔语谱图
语谱图(五) Mel_语谱图之MFCC系数
信号处理(二)音频信号的分帧, 加窗
梅尔频率倒谱系数(MFCC)的提取过程与C++代码实现

5、QMediaPlayer

Qt6中重大改变的QtMultimedia多媒体模块实现
QtPotPlayer

  • 0
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
本课程详细、全面地介绍了 Qt 开发中的各个技术细节,并且额外赠送在嵌入式端编写Qt程序的技巧。整个课程涵盖知识点非常多,知识模块囊括 Qt-Core 组件、QWidgets、多媒体、网络、绘图、数据库,超过200个 C++ 类的分析和使用,学完之后将拥有 Qt 图形界面开发的非常坚实的功底。 每个知识点不仅仅会通过视频讲解清楚,并且会配以精心安排的实验和作业,用来保证学习过程中切实掌握核心技术和概念,通过实验来巩固,通过实验来检验,实验与作业的目的是发现问题,发现技术盲点,通过答疑和沟通夯实技术技能。注意:本套视频教程来源于线下的实体班级,因此视频中有少量场景对话和学生问答,对此比较介意的亲们谨慎购买。注意:本套视频教程包含大量课堂源码,包含对应每个知识点的精心编排的作业。由于CSDN官方规定在课程介绍中不能出现作者的联系方式,因此在这里无法直接给出QQ答疑号,视频中的源码、资料和作业文档链接统一在购买后从CSDN平台跟我沟通,我会及时回复跟进。注意:本套视频教程包含全套10套作业题,覆盖所有视频知识点,循序渐进,各个击破,作业总纲如下:下面是部分作业题目展示,每道题都有知识点说明,是检验学习效果的一大利器:(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)…… ……
音频输出是指将音频数据从计算机传输到音频设备(如扬声器或耳机)以进行播放的过程。在C++中,Qt框架提供了一个名为QAudioOutput的类,用于实现音频输出功能。 QAudioOutput类允许开发人员将音频数据写入缓冲区,并将其发送到音频设备进行播放。它提供了一种简单的方法来处理音频输出,并且支持多种音频格式和配置选项。 使用QAudioOutput类,您可以执行以下操作: - 设置音频格式和配置选项,如采样率、声道数和样本大小。 - 写入音频数据到缓冲区,并将其发送到音频设备进行播放。 - 控制音频的开始、暂停和停止。 - 监听音频输出状态的变化,如缓冲区的填充状态和错误信息。 以下是使用QAudioOutput类的简单示例: ```cpp #include <QAudioOutput> #include <QIODevice> int main() { // 创建QAudioFormat对象,配置音频格式 QAudioFormat format; format.setSampleRate(44100); format.setChannelCount(2); format.setSampleSize(16); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); // 创建QAudioOutput对象,并设置音频格式 QAudioOutput audioOutput(format); // 打开音频输出设备 audioOutput.start(); // 创建QIODevice对象,用于写入音频数据 QIODevice *outputIODevice = audioOutput.start(); // 向QIODevice写入音频数据 outputIODevice->write(audioData, dataSize); // 暂停音频输出 audioOutput.suspend(); // 恢复音频输出 audioOutput.resume(); // 停止音频输出 audioOutput.stop(); return 0; } ``` 此示例演示了如何使用QAudioOutput类进行简单的音频输出。您可以根据自己的需求配置音频格式,并使用QIODevice对象写入音频数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值