当前位置: 首页 > news >正文

开源 C++ QT QML 开发(十九)多媒体--音频录制

           文章的目的为了记录使用QT QML开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

 相关链接:

开源 C++ QT QML 开发(一)基本介绍

开源 C++ QT QML 开发(二)工程结构

开源 C++ QT QML 开发(三)常用控件

开源 C++ QT QML 开发(四)复杂控件--Listview

开源 C++ QT QML 开发(五)复杂控件--Gridview

开源 C++ QT QML 开发(六)自定义控件--波形图

开源 C++ QT QML 开发(七)自定义控件--仪表盘

开源 C++ QT QML 开发(八)自定义控件--圆环

开源 C++ QT QML 开发(九)文件--文本和二进制

开源 C++ QT QML 开发(十)通讯--串口

开源 C++ QT QML 开发(十一)通讯--TCP服务器端

开源 C++ QT QML 开发(十二)通讯--TCP客户端

开源 C++ QT QML 开发(十三)多线程

开源 C++ QT QML 开发(十四)进程用途

开源 C++ QT QML 开发(十五)通讯--http下载

开源 C++ QT QML 开发(十六)进程--共享内存

开源 C++ QT QML 开发(十七)进程--LocalSocket

开源 C++ QT QML 开发(十八)多媒体--音频播放

推荐链接:

开源 C# 快速开发(一)基础知识

开源 C# 快速开发(二)基础控件

开源 C# 快速开发(三)复杂控件

开源 C# 快速开发(四)自定义控件--波形图

开源 C# 快速开发(五)自定义控件--仪表盘

开源 C# 快速开发(六)自定义控件--圆环

开源 C# 快速开发(七)通讯--串口

开源 C# 快速开发(八)通讯--Tcp服务器端

开源 C# 快速开发(九)通讯--Tcp客户端

开源 C# 快速开发(十)通讯--http客户端

开源 C# 快速开发(十一)线程

开源 C# 快速开发(十二)进程监控

开源 C# 快速开发(十三)进程--管道通讯

开源 C# 快速开发(十四)进程--内存映射

开源 C# 快速开发(十五)进程--windows消息

开源 C# 快速开发(十六)数据库--sqlserver增删改查

本章节主要内容是:qml的多媒体音频的录制,保存为wav的16KHz格式。

1.代码分析

2.所有源码

3.效果演示

一、代码分析

1. AudioManager 类分析
1.1 构造函数 AudioManager::AudioManager()
 

AudioManager::AudioManager(QObject *parent): QObject(parent), m_audioInput(nullptr), m_outputFile(nullptr), m_buffer(nullptr), m_timer(new QTimer(this)), m_isRecording(false), m_audioDuration(0), m_statusText("就绪"), m_timeText("00:00"), m_progress(0), m_logText("")
{// 连接计时器信号到更新进度槽函数connect(m_timer, &QTimer::timeout, this, &AudioManager::updateProgress);// 记录启动日志logMessage("程序启动完成");
}


功能分析:

初始化所有成员变量:将指针变量初始化为nullptr,布尔值初始化为false,数值初始化为0,字符串初始化为默认值

创建计时器:QTimer用于定期更新录音进度显示

信号槽连接:将计时器的timeout信号连接到updateProgress槽函数,每100ms触发一次

初始状态设置:设置初始状态文本、时间显示和进度

日志记录:调用logMessage记录程序启动信息

1.2 析构函数 AudioManager::~AudioManager()
 

AudioManager::~AudioManager()
{stopRecording();
}


功能分析:

资源清理:在对象销毁时自动调用stopRecording()确保录音被正确停止

防止资源泄漏:确保所有动态分配的资源被正确释放


1.3 音频输入设置 AudioManager::setupAudioInput()
 

void AudioManager::setupAudioInput()
{// 设置音频格式:16kHz, 16位, 单声道QAudioFormat format;format.setSampleRate(16000);        // 采样率16kHzformat.setChannelCount(1);          // 单声道format.setSampleSize(16);           // 16位采样大小format.setCodec("audio/pcm");       // PCM编码format.setByteOrder(QAudioFormat::LittleEndian);  // 小端字节序format.setSampleType(QAudioFormat::SignedInt);    // 有符号整数// 检查格式支持QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();if (!info.isFormatSupported(format)) {logMessage("警告:默认格式不支持,使用最近似格式");format = info.nearestFormat(format);  // 获取最接近的格式}// 记录音频格式信息logMessage(QString("音频格式:%1Hz, %2位, %3声道").arg(format.sampleRate()).arg(format.sampleSize()).arg(format.channelCount()));// 创建音频输入对象m_audioInput = new QAudioInput(format, this);
}


功能分析:

音频格式配置:设置标准的PCM音频格式参数

硬件兼容性检查:检查默认音频设备是否支持指定格式

格式自适应:如果不支持则使用最接近的格式

日志记录:记录最终使用的音频格式信息

对象创建:创建QAudioInput对象用于音频输入


1.4 开始录音 AudioManager::startRecording()
 

void AudioManager::startRecording()
{if (m_isRecording) return;  // 防止重复开始logMessage("开始录音...");// 设置音频输入setupAudioInput();// 创建输出文件QString filePath = QDir::currentPath() + "/input.wav";m_outputFile = new QFile(filePath, this);if (!m_outputFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) {logMessage("错误:无法创建文件");delete m_outputFile;m_outputFile = nullptr;return;}// 先写入空的WAV文件头setupWavHeader(*m_outputFile, 0);// 创建缓冲区m_buffer = new QBuffer(this);m_buffer->open(QIODevice::ReadWrite);// 开始录音m_audioInput->start(m_buffer);m_isRecording = true;// 启动计时器m_timer->start(100);  // 100ms间隔m_audioDuration = 0;// 更新状态m_statusText = "正在录音...";m_progress = 0;m_timeText = "00:00";// 发出属性变化信号emit isRecordingChanged();emit statusTextChanged();emit timeTextChanged();emit progressChanged();logMessage("录音进行中");
}


功能分析:

状态检查:防止在录音状态下重复开始

资源初始化:依次初始化音频输入、输出文件、缓冲区

文件操作:创建WAV文件并写入初始文件头

缓冲区设置:创建内存缓冲区存储音频数据

启动录音:调用QAudioInput的start()方法开始录音

计时器启动:开始计时器用于更新UI

状态更新:更新所有相关状态变量

信号发射:通知QML界面更新显示


1.5 停止录音 AudioManager::stopRecording()
 

void AudioManager::stopRecording()
{if (!m_isRecording) return;  // 如果不在录音状态,直接返回logMessage("停止录音...");// 停止录音m_audioInput->stop();m_isRecording = false;// 停止计时器m_timer->stop();// 写入音频数据到文件if (m_buffer && m_outputFile) {QByteArray audioData = m_buffer->data();m_outputFile->seek(0);  // 回到文件开头setupWavHeader(*m_outputFile, audioData.size());  // 重新写入正确的文件头m_outputFile->write(audioData);  // 写入音频数据m_outputFile->close();logMessage(QString("录音完成,文件大小:%1 字节").arg(audioData.size()));}// 清理资源if (m_buffer) {m_buffer->close();m_buffer->deleteLater();m_buffer = nullptr;}if (m_outputFile) {m_outputFile->deleteLater();m_outputFile = nullptr;}if (m_audioInput) {m_audioInput->deleteLater();m_audioInput = nullptr;}// 更新状态m_statusText = "录音完成";m_progress = 100;// 发出属性变化信号emit isRecordingChanged();emit statusTextChanged();emit progressChanged();
}


功能分析:

状态检查:确保在录音状态下才执行停止操作

停止录音:调用QAudioInput的stop()方法

停止计时器:停止进度更新

文件处理:

获取缓冲区中的音频数据

重新写入正确的WAV文件头(包含实际数据大小)

写入音频数据并关闭文件

资源清理:使用deleteLater安全删除对象

状态更新:更新UI状态为完成


1.6 更新进度 AudioManager::updateProgress()
 

void AudioManager::updateProgress()
{m_audioDuration += 100;  // 每次增加100msint seconds = m_audioDuration / 1000;  // 转换为秒// 格式化时间显示:MM:SSm_timeText = QString("%1:%2").arg(seconds / 60, 2, 10, QLatin1Char('0'))  // 分钟,2位,补0.arg(seconds % 60, 2, 10, QLatin1Char('0')); // 秒钟,2位,补0m_progress = qMin(100, seconds);  // 进度最大100%// 发出变化信号emit timeTextChanged();emit progressChanged();
}


功能分析:

时间累计:每次调用增加100ms录音时间

时间格式化:将毫秒转换为MM:SS格式的字符串

进度计算:每秒增加1%进度,最大100%

信号发射:通知QML更新时间显示和进度条


1.7 WAV文件头设置 AudioManager::setupWavHeader()
 

void AudioManager::setupWavHeader(QFile &file, quint32 dataSize)
{// WAV文件头结构struct WavHeader {char riff[4] = {'R','I','F','F'};        // "RIFF"标识quint32 chunkSize;                       // 文件总大小-8char wave[4] = {'W','A','V','E'};        // "WAVE"标识char fmt[4] = {'f','m','t',' '};         // "fmt "标识quint32 fmtChunkSize = 16;               // fmt块大小quint16 audioFormat = 1;                 // 音频格式:1=PCMquint16 numChannels = 1;                 // 声道数quint32 sampleRate = 16000;              // 采样率quint32 byteRate;                        // 字节率quint16 blockAlign;                      // 块对齐quint16 bitsPerSample = 16;              // 位深度char data[4] = {'d','a','t','a'};        // "data"标识quint32 dataChunkSize;                   // 数据块大小};WavHeader header;header.chunkSize = 36 + dataSize;           // 文件总大小-8header.byteRate = 16000 * 1 * 16 / 8;       // 采样率 × 声道数 × 位深度 / 8header.blockAlign = 1 * 16 / 8;             // 声道数 × 位深度 / 8header.dataChunkSize = dataSize;            // 音频数据大小// 写入文件头到文件file.write(reinterpret_cast<const char*>(&header), sizeof(WavHeader));
}


功能分析:

WAV文件结构:定义标准的WAV文件头结构

参数计算:

chunkSize = 36 + 数据大小(文件总大小-8)

byteRate = 采样率 × 声道数 × 位深度 ÷ 8

blockAlign = 声道数 × 位深度 ÷ 8

二进制写入:将结构体以二进制形式写入文件

1.8 日志记录 AudioManager::logMessage()
 

void AudioManager::logMessage(const QString &message)
{QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);// 添加换行符(如果不是第一条日志)if (!m_logText.isEmpty()) {m_logText += "\n";}m_logText += logEntry;// 发出日志变化信号emit logTextChanged();// 同时输出到调试控制台qDebug() << message;
}


功能分析:

时间戳生成:获取当前时间并格式化为hh:mm:ss

日志格式化:组合时间戳和消息内容

日志累积:在现有日志后追加新日志,用换行符分隔

信号通知:通知QML界面更新日志显示

调试输出:同时输出到qDebug便于调试


2. Main函数分析
2.1 应用程序初始化 main()
 

int main(int argc, char *argv[])
{// 启用高DPI缩放QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);// 创建GUI应用程序QGuiApplication app(argc, argv);// 设置应用程序信息app.setApplicationName("音频录音机");app.setApplicationVersion("1.0");app.setOrganizationName("MyCompany");// 注册AudioManager类到QML系统qmlRegisterType<AudioManager>("AudioRecorder", 1, 0, "AudioManager");// 创建QML引擎QQmlApplicationEngine engine;// 创建全局AudioManager实例并设置为上下文属性AudioManager *audioManager = new AudioManager(&app);engine.rootContext()->setContextProperty("audioManager", audioManager);// 加载QML文件const QUrl url(QStringLiteral("qrc:/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);engine.load(url);// 检查QML加载是否成功if (engine.rootObjects().isEmpty()) {return -1;}// 进入事件循环return app.exec();
}


功能分析:

应用程序配置:设置高DPI缩放和应用信息

QML类型注册:将C++类注册到QML系统中

上下文属性设置:创建AudioManager实例并使其在QML中可用

QML加载:加载并显示QML界面

错误处理:检查QML加载是否成功

事件循环:启动Qt事件循环


3. QML界面分析
3.1 主窗口结构
 

ApplicationWindow {id: windowwidth: 600height: 500title: "音频录音机 - QML版本"visible: true// 背景渐变Rectangle {anchors.fill: parentgradient: Gradient {GradientStop { position: 0.0; color: "#2c3e50" }GradientStop { position: 1.0; color: "#34495e" }}}// ... 其他组件
}


功能分析:

窗口设置:定义窗口大小、标题和可见性

背景设计:使用渐变背景创造现代感界面

3.2 录音按钮实现
 

Button {id: recordButtontext: audioManager.isRecording ? "停止录音" : "开始录音"// ... 其他属性background: Rectangle {radius: 30color: audioManager.isRecording ? "#e74c3c" : "#2ecc71"// ... 其他属性Behavior on color {ColorAnimation { duration: 300 }}}onClicked: {if (audioManager.isRecording) {audioManager.stopRecording()} else {audioManager.startRecording()}}
}


功能分析:

动态文本:根据录音状态显示不同文本

颜色切换:录音时显示红色,停止时显示绿色

动画效果:颜色变化时有300ms的过渡动画

点击处理:调用C++的start/stopRecording方法


3.3 数据绑定机制
 

// 状态文本绑定
Label {text: audioManager.statusText  // 自动绑定到C++属性
}// 时间显示绑定  
Label {text: audioManager.timeText    // 自动绑定到C++属性
}// 进度条绑定
ProgressBar {value: audioManager.progress   // 自动绑定到C++属性
}// 日志显示绑定
TextArea {text: audioManager.logText     // 自动绑定到C++属性
}


功能分析:

自动更新:当C++端属性变化并发出信号时,QML界面自动更新

双向通信:C++逻辑控制业务,QML界面负责显示和用户交互

4. 程序架构总结
这个录音程序采用了典型的MVC架构:

Model:AudioManager类,负责所有录音逻辑和数据处理

View:QML界面,负责用户界面显示和交互

Controller:QML中的事件处理和数据绑定

数据流:

用户点击QML按钮

QML调用C++的录音方法

C++处理录音逻辑并更新属性

C++发出属性变化信号

QML自动更新界面显示

二、所有源码

audiomanager.h文件源码

#ifndef AUDIOMANAGER_H
#define AUDIOMANAGER_H#include <QObject>
#include <QAudioInput>
#include <QAudioFormat>
#include <QFile>
#include <QBuffer>
#include <QTimer>
#include <QDateTime>class AudioManager : public QObject
{Q_OBJECTQ_PROPERTY(bool isRecording READ isRecording NOTIFY isRecordingChanged)Q_PROPERTY(QString statusText READ statusText NOTIFY statusTextChanged)Q_PROPERTY(QString timeText READ timeText NOTIFY timeTextChanged)Q_PROPERTY(int progress READ progress NOTIFY progressChanged)Q_PROPERTY(QString logText READ logText NOTIFY logTextChanged)public:explicit AudioManager(QObject *parent = nullptr);~AudioManager();bool isRecording() const { return m_isRecording; }QString statusText() const { return m_statusText; }QString timeText() const { return m_timeText; }int progress() const { return m_progress; }QString logText() const { return m_logText; }Q_INVOKABLE void startRecording();Q_INVOKABLE void stopRecording();private slots:void updateProgress();private:void setupAudioInput();void setupWavHeader(QFile &file, quint32 dataSize);void logMessage(const QString &message);QAudioInput *m_audioInput;QFile *m_outputFile;QBuffer *m_buffer;QTimer *m_timer;bool m_isRecording;int m_audioDuration;// Q_PROPERTY backing fieldsQString m_statusText;QString m_timeText;int m_progress;QString m_logText;signals:void isRecordingChanged();void statusTextChanged();void timeTextChanged();void progressChanged();void logTextChanged();
};#endif // AUDIOMANAGER_H

audiomanager.cpp文件源码

#include "audiomanager.h"
#include <QAudioDeviceInfo>
#include <QDir>
#include <QDebug>
#include <cmath>AudioManager::AudioManager(QObject *parent): QObject(parent), m_audioInput(nullptr), m_outputFile(nullptr), m_buffer(nullptr), m_timer(new QTimer(this)), m_isRecording(false), m_audioDuration(0), m_statusText("就绪"), m_timeText("00:00"), m_progress(0), m_logText("")
{connect(m_timer, &QTimer::timeout, this, &AudioManager::updateProgress);logMessage("程序启动完成");
}AudioManager::~AudioManager()
{stopRecording();
}void AudioManager::setupAudioInput()
{// 设置音频格式:16kHz, 16位, 单声道QAudioFormat format;format.setSampleRate(16000);format.setChannelCount(1);format.setSampleSize(16);format.setCodec("audio/pcm");format.setByteOrder(QAudioFormat::LittleEndian);format.setSampleType(QAudioFormat::SignedInt);// 检查格式支持QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();if (!info.isFormatSupported(format)) {logMessage("警告:默认格式不支持,使用最近似格式");format = info.nearestFormat(format);}logMessage(QString("音频格式:%1Hz, %2位, %3声道").arg(format.sampleRate()).arg(format.sampleSize()).arg(format.channelCount()));m_audioInput = new QAudioInput(format, this);
}void AudioManager::startRecording()
{if (m_isRecording) return;logMessage("开始录音...");// 设置音频输入setupAudioInput();// 创建输出文件QString filePath = QDir::currentPath() + "/input.wav";m_outputFile = new QFile(filePath, this);if (!m_outputFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) {logMessage("错误:无法创建文件");delete m_outputFile;m_outputFile = nullptr;return;}// 先写入空的WAV文件头setupWavHeader(*m_outputFile, 0);// 创建缓冲区m_buffer = new QBuffer(this);m_buffer->open(QIODevice::ReadWrite);// 开始录音m_audioInput->start(m_buffer);m_isRecording = true;// 启动计时器m_timer->start(100);m_audioDuration = 0;// 更新状态m_statusText = "正在录音...";m_progress = 0;m_timeText = "00:00";emit isRecordingChanged();emit statusTextChanged();emit timeTextChanged();emit progressChanged();logMessage("录音进行中");
}void AudioManager::stopRecording()
{if (!m_isRecording) return;logMessage("停止录音...");// 停止录音m_audioInput->stop();m_isRecording = false;// 停止计时器m_timer->stop();// 写入音频数据到文件if (m_buffer && m_outputFile) {QByteArray audioData = m_buffer->data();m_outputFile->seek(0);setupWavHeader(*m_outputFile, audioData.size());m_outputFile->write(audioData);m_outputFile->close();logMessage(QString("录音完成,文件大小:%1 字节").arg(audioData.size()));}// 清理资源if (m_buffer) {m_buffer->close();m_buffer->deleteLater();m_buffer = nullptr;}if (m_outputFile) {m_outputFile->deleteLater();m_outputFile = nullptr;}if (m_audioInput) {m_audioInput->deleteLater();m_audioInput = nullptr;}// 更新状态m_statusText = "录音完成";m_progress = 100;emit isRecordingChanged();emit statusTextChanged();emit progressChanged();
}void AudioManager::updateProgress()
{m_audioDuration += 100;int seconds = m_audioDuration / 1000;m_timeText = QString("%1:%2").arg(seconds / 60, 2, 10, QLatin1Char('0')).arg(seconds % 60, 2, 10, QLatin1Char('0'));m_progress = qMin(100, seconds);emit timeTextChanged();emit progressChanged();
}void AudioManager::setupWavHeader(QFile &file, quint32 dataSize)
{// WAV文件头结构struct WavHeader {char riff[4] = {'R','I','F','F'};quint32 chunkSize;char wave[4] = {'W','A','V','E'};char fmt[4] = {'f','m','t',' '};quint32 fmtChunkSize = 16;quint16 audioFormat = 1; // PCMquint16 numChannels = 1;quint32 sampleRate = 16000;quint32 byteRate;quint16 blockAlign;quint16 bitsPerSample = 16;char data[4] = {'d','a','t','a'};quint32 dataChunkSize;};WavHeader header;header.chunkSize = 36 + dataSize;header.byteRate = 16000 * 1 * 16 / 8; // sampleRate * channels * bitsPerSample / 8header.blockAlign = 1 * 16 / 8; // channels * bitsPerSample / 8header.dataChunkSize = dataSize;file.write(reinterpret_cast<const char*>(&header), sizeof(WavHeader));
}void AudioManager::logMessage(const QString &message)
{QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);if (!m_logText.isEmpty()) {m_logText += "\n";}m_logText += logEntry;emit logTextChanged();qDebug() << message;
}

main.qml文件源码

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14ApplicationWindow {id: windowwidth: 600height: 500title: "音频录音机 - QML版本"visible: true// 背景渐变Rectangle {anchors.fill: parentgradient: Gradient {GradientStop { position: 0.0; color: "#2c3e50" }GradientStop { position: 1.0; color: "#34495e" }}}ColumnLayout {anchors.fill: parentanchors.margins: 20spacing: 15// 标题Label {text: "音频录音机"Layout.alignment: Qt.AlignHCentercolor: "white"font.pixelSize: 28font.bold: true}// 状态显示区域Rectangle {Layout.fillWidth: trueLayout.preferredHeight: 120color: "#34495e"radius: 10border.color: "#3498db"border.width: 2ColumnLayout {anchors.fill: parentanchors.margins: 15spacing: 10// 状态标签Label {text: audioManager.statusTextLayout.fillWidth: truecolor: "white"font.pixelSize: 18horizontalAlignment: Text.AlignHCenter}// 时间显示Label {text: audioManager.timeTextLayout.fillWidth: truecolor: "#e74c3c"font.pixelSize: 32font.bold: truehorizontalAlignment: Text.AlignHCenter}// 进度条ProgressBar {id: progressBarLayout.fillWidth: truefrom: 0to: 100value: audioManager.progressbackground: Rectangle {implicitWidth: 200implicitHeight: 6color: "#2c3e50"radius: 3}contentItem: Item {implicitWidth: 200implicitHeight: 4Rectangle {width: progressBar.visualPosition * parent.widthheight: parent.heightradius: 2gradient: Gradient {GradientStop { position: 0.0; color: "#3498db" }GradientStop { position: 1.0; color: "#2980b9" }}}}}}}// 录音按钮Button {id: recordButtonLayout.alignment: Qt.AlignHCenterLayout.preferredWidth: 200Layout.preferredHeight: 60text: audioManager.isRecording ? "停止录音" : "开始录音"font.pixelSize: 18font.bold: truebackground: Rectangle {radius: 30color: audioManager.isRecording ? "#e74c3c" : "#2ecc71"border.color: audioManager.isRecording ? "#c0392b" : "#27ae60"border.width: 3Behavior on color {ColorAnimation { duration: 300 }}}contentItem: Text {text: recordButton.textfont: recordButton.fontcolor: "white"horizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenter}onClicked: {if (audioManager.isRecording) {audioManager.stopRecording()} else {audioManager.startRecording()}}}// 日志区域Rectangle {Layout.fillWidth: trueLayout.fillHeight: truecolor: "#1e272e"radius: 10border.color: "#7f8c8d"border.width: 1ColumnLayout {anchors.fill: parentspacing: 5Label {text: "操作日志"color: "#bdc3c7"font.pixelSize: 16font.bold: trueLayout.leftMargin: 10Layout.topMargin: 5}ScrollView {Layout.fillWidth: trueLayout.fillHeight: trueLayout.margins: 10TextArea {id: logTextAreatext: audioManager.logTextcolor: "#ecf0f1"font.pixelSize: 12font.family: "Consolas, Monaco, monospace"wrapMode: Text.WrapreadOnly: trueselectByMouse: truebackground: Rectangle {color: "transparent"}}}}}// 底部信息Label {text: "基于Qt5.14 QML的录音程序 | 支持WAV格式 | 16kHz 16位 单声道"Layout.alignment: Qt.AlignHCentercolor: "#95a5a6"font.pixelSize: 12}}// 录音时的动画效果Rectangle {id: recordingIndicatorwidth: 20height: 20radius: 10color: "#e74c3c"visible: audioManager.isRecordinganchors.top: parent.topanchors.right: parent.rightanchors.margins: 15SequentialAnimation on opacity {running: recordingIndicator.visibleloops: Animation.InfiniteNumberAnimation { from: 0.3; to: 1.0; duration: 800 }NumberAnimation { from: 1.0; to: 0.3; duration: 800 }}}
}

main.cpp文件源码

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "audiomanager.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);// 设置应用程序信息app.setApplicationName("音频录音机");app.setApplicationVersion("1.0");app.setOrganizationName("MyCompany");// 注册AudioManager类到QMLqmlRegisterType<AudioManager>("AudioRecorder", 1, 0, "AudioManager");QQmlApplicationEngine engine;// 创建全局AudioManager实例AudioManager *audioManager = new AudioManager(&app);engine.rootContext()->setContextProperty("audioManager", audioManager);const QUrl url(QStringLiteral("qrc:/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);engine.load(url);if (engine.rootObjects().isEmpty()) {return -1;}return app.exec();
}

三、效果演示

http://www.dtcms.com/a/481853.html

相关文章:

  • json转excel python
  • 在传输数据时,网络中会出现的问题
  • jenkins在使用中遇到的问题
  • 第8章 zynq uboot更新系统镜像并引导启动和个人心得
  • 网站系统升级建设合同汽车之家官网首页网页
  • 电销外包公司有哪些seo学习网站
  • 基于弱监督病灶增强的模型展开式快速磁共振成像|文献速递-文献分享
  • 十四、OpenCV中的形态学操作
  • 算法279. 完全平方数
  • Prometheus pushgateway学习
  • MySQL索引结构:B树与B+树
  • 进程的基本认识
  • Webpack 打包优化与骨架屏结合:双管齐下提升前端性能与用户体验
  • 鸿蒙:在沙箱目录下压缩或解压文件
  • 智能SQL客户端Chat2DB技术解析
  • 电影网站推广什么是网络营销的主要职能之一
  • Transformers库用法示例:解锁预训练模型的强大能力
  • 大气污染扩散calpuff模型:数据预处理、Calmet气象模块、Post Tools 后处理工具及绘图工具
  • 用气安全与能效优化平台
  • 02117 信息组织【第三章】
  • 自己建设淘宝客网站需要备案么wordpress插件 投票
  • Wireshark 4.4.9 设置为中文界面方法
  • 极限AI Coding,腾讯云“黑客松”大赛回顾(内有作品开源)
  • 【工具分享】Dota游戏平台助手
  • 网站制作找云优化口碑好的网站定制公司
  • 精品建站公司2345网址大全下载到桌面
  • HENGSHI SENSE异构过滤架构:基于三层执行引擎的跨源联邦查询性能优化实践
  • 语言模型监督式微调(SFT)概述
  • 又开始了 小程序定制
  • 前端面试-箭头函数