Qt-播放录制pcm音频显示频谱

 界面就是几个按钮,和几个label组成的

1.头文件

#ifndef WAVE_HEAD_H
#define WAVE_HEAD_H
struct wave_riff{
    char cid[4];
    unsigned long cs;
    char format[4];
};

struct wave_fmt{
    char sid[4];
    unsigned long s1s;
    unsigned short int af;
    unsigned short int nc;
    unsigned int sr;
    unsigned int br;
    unsigned short int ba;
    unsigned short int bps;
};

struct wave_data{
    char s2id[4];
    unsigned long s2s;
};



#endif // WAVE_HEAD_H

wave pcm头 格式

没有这个也可以播放,添加wave头之后计算机可以播放wave文件否则,播放器不识别。

2.widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QFile>
#include <QAudioFormat>
#include <QAudioOutput>
#include <QAudioInput>
#include <QTimer>
#include <QTimeEdit>
#include <QtDebug>
#include <QPainter>
#include <QPaintEvent>
#include <QEvent>
#include <WAVE_HEAD.h>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_pushButton_clicked();
    void on_inpput_clicked();
    void stopRecording();
    void handleStateChanged(QAudio::State newState);
    void on_stop_clicked();
    void on_button_stop_clicked();
    void on_button_see_clicked();
protected:
    bool eventFilter(QObject *obj,QEvent *event) override;
    void timerEvent(QTimerEvent* e) override;
    void paintEvent(QPaintEvent *event) override;
    void paint();
private:
    Ui::Widget *ui;
    QAudioInput* audio;
    QAudioOutput* audioOut;
    QFile destinationFile;   // Class member
    QFile sourceFile;
    QByteArray ba;
    int tid;
    int r,g,b;
    int r1,g1,b1;
    int r2,g2,b2;
    wave_riff riff;
    wave_fmt fmt;
    wave_data data;
private:
    void ini_wave_head();
};
#endif // WIDGET_H

3.widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    :QWidget(parent)
    ,ui(new Ui::Widget)
{
    ui->setupUi(this);
    audio=nullptr;
    audioOut=nullptr;
    ui->label->installEventFilter(this);

}

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

//播放
void Widget::on_pushButton_clicked()
{
    sourceFile.setFileName("/test.pcm");
    bool bl = sourceFile.open(QIODevice::ReadOnly);
    if(bl == true){
        QAudioFormat format;
        format.setSampleRate(44100);
        format.setChannelCount(2);
        format.setSampleSize(16);
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::UnSignedInt);
        audioOut = new QAudioOutput(format,0);
        connect(audioOut,SIGNAL(stateChanged(QAudio::State)),this, SLOT(handleStateChanged(QAudio::State)));
        audioOut->start(&sourceFile);
        ui->state->setText("开始播放");
    }else
    {
        qDebug()<<"no file";
    }
}

//录制
void Widget::on_inpput_clicked()
{
    {
        destinationFile.setFileName("/test12.pcm");
        destinationFile.open( QIODevice::WriteOnly | QIODevice::Truncate);
        ini_wave_head();
        destinationFile.write((char *)&riff);
        destinationFile.write((char *)&fmt);
        destinationFile.write((char *)&data);

        QAudioFormat format;
        // Set up the desired format, for example:
        //设置采样率
        format.setSampleRate(11025);
        //设置通道数
        format.setChannelCount(1);
        //设置采样大小,一般为8位或16位
        format.setSampleSize(16);
        //设置编码方式
        format.setCodec("audio/pcm");
        //设置字节序
        format.setByteOrder(QAudioFormat::LittleEndian);
        //设置样本数据类型
        format.setSampleType(QAudioFormat::UnSignedInt);
        QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
        info.supportedCodecs();
        if(!info.isFormatSupported(format)){
            qWarning() << "Default format not supported, trying to use the nearest.";
            format = info.nearestFormat(format);
        }else{
            audio = new QAudioInput(format, this);
            audio->start(&destinationFile);
            qDebug()<<audio->bufferSize();
            ui->state->setText("开始录制");
        }
    }
}

void Widget::stopRecording()
{
    audio->stop();
    destinationFile.close();
    delete audio;
}

void Widget::handleStateChanged(QAudio::State newState)
{
    switch(newState) {
    case QAudio::StoppedState:
        if (audio->error() != QAudio::NoError||audioOut->error()!=QAudio::NoError) {
            // Error handling
            qDebug()<<audio->error()<<audioOut->error();
        } else {
            // Finished recording
        }
        break;
    case QAudio::ActiveState:
        ui->state->setText("活动状态");
        break;
    case QAudio::IdleState:
        ui->state->setText("空闲状态");
        break;
    case QAudio::SuspendedState:
        ui->state->setText("暂停状态");
        break;
    default:
        // ... other cases as appropriate
        break;
    }
}

void Widget::on_stop_clicked()
{
    audio->stop();
    destinationFile.close();
    delete audio;
    ui->state->setText("录制结束文件保存在/");
}

void Widget::on_button_stop_clicked()
{
    if(ui->button_stop->text()=="暂停"){
        ui->button_stop->setText("继续");
        audioOut->suspend();
    }else{
        audioOut->start(&sourceFile);
    }
}

//显示波形
void Widget::on_button_see_clicked()
{
    QFile file("/test.pcm");
    if(file.open(QFile::ReadOnly)){
        ba = file.readAll();
        tid = this->startTimer(10);
        ui->state->setText("文件已加载");
        ui->pushButton->click();
    }
    r=qrand()%255;
    g=qrand()%255;
    b=qrand()%255;
    r1=qrand()%255;
    g1=qrand()%255;
    b1=qrand()%255;
    r2=qrand()%255;
    g2=qrand()%255;
    b2=qrand()%255;
    file.close();
}


bool Widget::eventFilter(QObject *obj, QEvent *event)
{
    if(obj ==ui->label && event->type() == QEvent::Paint)
        paint();

    return QWidget::eventFilter(obj,event);
}

void Widget::timerEvent(QTimerEvent *e)
{
    if(tid == e->timerId()){
        //paint();
        update();
        //qDebug()<<tid<<e->timerId();
    }
}


void Widget::paintEvent(QPaintEvent *event)
{

}

void Widget::paint()
{

    static int start_index=0;
    const int n = 1764;
    static int v = 0;
    static int starty=ui->label->height();

    qsrand(time(NULL));

    QPainter *p = new QPainter(ui->label);

    QByteArray temp;

    /*从start_index开始截取n个字节*/
    temp = ba.mid(start_index,n);

    if(temp.length()>0&&start_index<ba.length()){
        for(int i=0;i<temp.length();i++){
            v=ui->label->height()/2 - temp.at(i);
            /*画数据*/
            p->setRenderHint(QPainter::Antialiasing,true);
            QLinearGradient lg(i,starty,i,v);

            lg.setColorAt(0.236029032, QColor(r,g,b));

            lg.setColorAt(0.381924, QColor(r1,g1,b1));

            lg.setColorAt(0.618, QColor(r2,g2,b2));

            p->setPen(QPen(QBrush(lg),1));
            p->drawLine(i,starty,i,v);
        }
        /*从start_index位置+n个字节*/
        start_index+=n;
    }else if(temp.length()==0){
        /*如果没有数据则重置start_index*/
        start_index=0;
        /*关闭定时器*/
        tid=-1;
    }
    p->end();
}

void Widget::ini_wave_head()
{
    {
        riff.cid[0]='R';
        riff.cid[1]='I';
        riff.cid[2]='F';
        riff.cid[3]='F';
        riff.cs=123123;
        riff.format[0]='W';
        riff.format[1]='A';
        riff.format[2]='V';
        riff.format[3]='E';
    }

    {
        fmt.sid[0]='f';
        fmt.sid[1]='m';
        fmt.sid[2]='t';
        fmt.sid[3]=' ';
        fmt.s1s=16;
        fmt.af=1;
        fmt.nc=1;
        fmt.sr=11025;
        fmt.br=1231;
        fmt.ba=123;
        fmt.bps=16;
    }

    {
        data.s2id[0]='d';
        data.s2id[1]='a';
        data.s2id[2]='t';
        data.s2id[3]='a';
        data.s2s=123123;
    }
}

 最终样子

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值