add wavmanager module.
add libqwav add voicetest2
202
src/multimedia/libqwav/libqwav.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
#include "libqwav.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
//header data tail
|
||||
bool addWavHeader ( QIODevice& outputDevice, const QAudioFormat& format )
|
||||
{
|
||||
// 开始设置WAV的文件头
|
||||
// 这里具体的数据代表什么含义请看上一篇文章(Qt之WAV文件解析)中对wav文件头的介绍
|
||||
WAVFILEHEADER WavFileHeader;
|
||||
qstrcpy ( WavFileHeader.RiffName, "RIFF" );
|
||||
qstrcpy ( WavFileHeader.WavName, "WAVE" );
|
||||
qstrcpy ( WavFileHeader.FmtName, "fmt " );
|
||||
qstrcpy ( WavFileHeader.DATANAME, "data" );
|
||||
|
||||
// 表示 FMT块 的长度
|
||||
WavFileHeader.nFmtLength = 16;
|
||||
|
||||
// 表示 按照PCM 编码;
|
||||
WavFileHeader.nAudioFormat = 1;
|
||||
// 声道数目;
|
||||
WavFileHeader.nChannleNumber = format.channelCount();
|
||||
// 采样频率;
|
||||
WavFileHeader.nSampleRate = format.sampleRate();
|
||||
//这个地方,int到unsinged int数据没有丢失。
|
||||
//pline() << WavFileHeader.nSampleRate << mFormat.sampleRate();
|
||||
// 每次采样得到的样本数据位数;
|
||||
WavFileHeader.nBitsPerSample = format.sampleSize();
|
||||
|
||||
// nBytesPerSample 和 nBytesPerSecond这两个值通过设置的参数计算得到;
|
||||
// 数据块对齐单位(每个采样需要的字节数 = 通道数 × 每次采样得到的样本数据位数 / 8 )
|
||||
WavFileHeader.nBlockAlign = WavFileHeader.nChannleNumber * WavFileHeader.nBitsPerSample / 8;
|
||||
// 波形数据传输速率
|
||||
// (每秒平均字节数 = 采样频率 × 通道数 × 每次采样得到的样本数据位数 / 8 = 采样频率 × 每个采样需要的字节数 )
|
||||
WavFileHeader.nBytesPerSecond = WavFileHeader.nSampleRate * WavFileHeader.nChannleNumber *
|
||||
WavFileHeader.nBitsPerSample / 8;
|
||||
|
||||
outputDevice.seek ( 0 );
|
||||
//riff 8 + 4
|
||||
WavFileHeader.nRiffLength = outputDevice.size() - 8;
|
||||
outputDevice.write ( WavFileHeader.RiffName, sizeof ( WavFileHeader.RiffName ) - 1 );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nRiffLength, sizeof ( WavFileHeader.nRiffLength ) );
|
||||
outputDevice.write ( WavFileHeader.WavName, sizeof ( WavFileHeader.WavName ) - 1 );
|
||||
|
||||
//fmt 8 + 16
|
||||
outputDevice.write ( WavFileHeader.FmtName, 4 );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nFmtLength, 4 );
|
||||
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nAudioFormat, sizeof ( WavFileHeader.nAudioFormat ) );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nChannleNumber, sizeof ( WavFileHeader.nChannleNumber ) );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nSampleRate, sizeof ( WavFileHeader.nSampleRate ) );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nBytesPerSecond, sizeof ( WavFileHeader.nBytesPerSecond ) );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nBlockAlign, sizeof ( WavFileHeader.nBlockAlign ) );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nBitsPerSample, sizeof ( WavFileHeader.nBitsPerSample ) );
|
||||
|
||||
//data 8
|
||||
outputDevice.write ( WavFileHeader.DATANAME, 4 );
|
||||
outputDevice.write ( ( char* ) &WavFileHeader.nDataLength, 4 );
|
||||
|
||||
WavFileHeader.fileHeaderSize = outputDevice.pos();
|
||||
|
||||
//44
|
||||
//int headerSize = WavFileHeader.fileHeaderSize;
|
||||
//qDebug() << headerSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addWavTail ( QIODevice& outputDevice )
|
||||
{
|
||||
QByteArray tailBytes;
|
||||
tailBytes += "q\xFCq\xFC";
|
||||
tailBytes += "a\xFB";
|
||||
tailBytes += "a\xFB";
|
||||
//8
|
||||
//pline() << tailBytes << tailBytes.size();
|
||||
outputDevice.write ( tailBytes );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool addWavDataBytes ( QIODevice& outputDevice, const QByteArray& bytes )
|
||||
{
|
||||
outputDevice.write ( bytes );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wavParse ( QString fileName, WAVFILEHEADER& WavFileHeader )
|
||||
{
|
||||
QFile fileInfo ( fileName );
|
||||
|
||||
if ( !fileInfo.open ( QIODevice::ReadOnly ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 警告:每一次读,都不seek的!用户调用了seek不会引发pos变化,read会。
|
||||
|
||||
// 读取 资源交换文件标志 "RIFF";
|
||||
fileInfo.read ( WavFileHeader.RiffName, sizeof ( WavFileHeader.RiffName ) - 1 );
|
||||
|
||||
// 读取 RIFF 头后字节数;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nRiffLength, sizeof ( WavFileHeader.nRiffLength ) );
|
||||
// 读取 波形文件标识符 "WAVE";
|
||||
fileInfo.read ( WavFileHeader.WavName, sizeof ( WavFileHeader.WavName ) - 1 );
|
||||
|
||||
// 警告:每一次读,都不seek的!用户调用了seek不会引发pos变化,read会。
|
||||
while ( 1 )
|
||||
{
|
||||
char tempName[5] = {0};
|
||||
unsigned int tempSize = 0;
|
||||
|
||||
fileInfo.read ( tempName, 4 );
|
||||
fileInfo.read ( ( char* ) &tempSize, 4 );
|
||||
|
||||
QString strTempName ( tempName );
|
||||
|
||||
if ( 0 == strTempName.compare ( "fmt ", Qt::CaseInsensitive ) )
|
||||
{
|
||||
strcpy ( WavFileHeader.FmtName, tempName );
|
||||
WavFileHeader.nFmtLength = tempSize;
|
||||
// 读取 格式种类;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nAudioFormat, sizeof ( WavFileHeader.nAudioFormat ) );
|
||||
// 读取 音频通道数目;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nChannleNumber, sizeof ( WavFileHeader.nChannleNumber ) );
|
||||
// 读取 采样频率;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nSampleRate, sizeof ( WavFileHeader.nSampleRate ) );
|
||||
// 读取 波形数据传输速率;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nBytesPerSecond, sizeof ( WavFileHeader.nBytesPerSecond ) );
|
||||
// 读取 数据块对齐单位;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nBlockAlign, sizeof ( WavFileHeader.nBlockAlign ) );
|
||||
// 读取 每次采样得到的样本数据位数值;
|
||||
fileInfo.read ( ( char* ) &WavFileHeader.nBitsPerSample, sizeof ( WavFileHeader.nBitsPerSample ) );
|
||||
// 如果有扩展字节
|
||||
fileInfo.read ( tempSize - 16 );
|
||||
}
|
||||
else if ( 0 == strTempName.compare ( "fact", Qt::CaseInsensitive ) )
|
||||
{
|
||||
// 存在fact块,读取数据;
|
||||
strcpy ( WavFileHeader.FactName, tempName );
|
||||
// fact块长度;
|
||||
WavFileHeader.nFactLength = tempSize;
|
||||
// 读取fact块数据;但是不处理
|
||||
fileInfo.read ( tempSize );
|
||||
qDebug() << "fact data" << tempName << tempSize;
|
||||
}
|
||||
else if ( 0 == strTempName.compare ( "data", Qt::CaseInsensitive ) )
|
||||
{
|
||||
strcpy ( WavFileHeader.DATANAME, tempName );
|
||||
WavFileHeader.nDataLength = tempSize;
|
||||
|
||||
// 读取 音频数据大小;
|
||||
WavFileHeader.fileDataSize = tempSize;
|
||||
//文件头大小;
|
||||
WavFileHeader.fileHeaderSize = fileInfo.pos();
|
||||
|
||||
// 注意:这里的总大小,包括结尾8个字节,wav文件有8个结尾字节。"q\xFCq\xFC""a\xFB""a\xFB"
|
||||
// 文件总大小;
|
||||
WavFileHeader.fileTotalSize = WavFileHeader.nRiffLength + 8;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "unhandled chunk" << tempName << tempSize;
|
||||
fileInfo.read ( tempSize );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//测试OK
|
||||
// pline() << "filesize" << WavFileHeader.fileTotalSize;
|
||||
// pline() << "fileheadersize" << WavFileHeader.fileHeaderSize;
|
||||
// pline() << "filedatasize" << WavFileHeader.fileDataSize;
|
||||
// pline() << "filetailsize" << WavFileHeader.fileTailSize;
|
||||
// pline() << WavFileHeader.nChannleNumber << WavFileHeader.nSampleRate << WavFileHeader.nBitsPerSample;
|
||||
|
||||
fileInfo.close();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 解析方法2 支援Qt 资源文件
|
||||
*/
|
||||
bool anlysisWavFileHeader ( QString fileName, QAudioFormat& format, TWavFileInfo& fileinfo )
|
||||
{
|
||||
WAVFILEHEADER WavFileHeader;
|
||||
bool ret = wavParse ( fileName, WavFileHeader );
|
||||
|
||||
format.setChannelCount ( WavFileHeader.nChannleNumber );
|
||||
format.setSampleRate ( WavFileHeader.nSampleRate );
|
||||
format.setSampleSize ( WavFileHeader.nBitsPerSample );
|
||||
format.setByteOrder ( QAudioFormat::LittleEndian );
|
||||
format.setCodec ( "audio/pcm" );
|
||||
format.setSampleType ( QAudioFormat::SignedInt );
|
||||
|
||||
fileinfo.fileTotalSize = WavFileHeader.fileTotalSize;
|
||||
fileinfo.fileHeaderSize = WavFileHeader.fileHeaderSize;
|
||||
fileinfo.fileDataSize = WavFileHeader.fileDataSize;
|
||||
fileinfo.fileTailSize = WavFileHeader.fileTailSize;
|
||||
return true;
|
||||
}
|
98
src/multimedia/libqwav/libqwav.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef LIBQWAV_H
|
||||
#define LIBQWAV_H
|
||||
|
||||
#include "libqwav_global.h"
|
||||
|
||||
#include "string.h"
|
||||
#include <QAudioFormat>
|
||||
#include <QIODevice>
|
||||
|
||||
//dll __imp_ lib no __imp_
|
||||
//跟这个extern没关系。
|
||||
//动态导出、导入时就是有__imp_
|
||||
//静态导出、导入时就是没有__imp_,导出的是函数原型。
|
||||
|
||||
//这个extern的作用是在导出库源文件是.c文件时,使用者必须使用extern "C"包含对应的头文件。
|
||||
//就这么一个作用。
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
|
||||
/*
|
||||
* 解析方法2 使用QtFile接口,支持Qt资源文件
|
||||
*/
|
||||
// wav文件头信息结构
|
||||
struct WAVFILEHEADER
|
||||
{
|
||||
// RIFF 头;
|
||||
char RiffName[5];//RIFF
|
||||
int nRiffLength;//fileLen-8
|
||||
// 数据类型标识符;
|
||||
char WavName[5];//WAVE
|
||||
|
||||
// 格式块中的块头;
|
||||
char FmtName[5];//fmt
|
||||
int nFmtLength;
|
||||
// 格式块中的块数据;
|
||||
short nAudioFormat;
|
||||
short nChannleNumber;
|
||||
int nSampleRate;
|
||||
int nBytesPerSecond;
|
||||
short nBlockAlign;
|
||||
short nBitsPerSample;
|
||||
|
||||
// 附加信息(可选),根据 nFmtLength 来判断;
|
||||
// 扩展域大小;
|
||||
short nAppendMessage;
|
||||
|
||||
//Fact块,可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk;
|
||||
char FactName[5];
|
||||
int nFactLength;
|
||||
|
||||
// DATA块,数据块中的块头;
|
||||
char DATANAME[5];
|
||||
int nDataLength;//fileDataSize
|
||||
|
||||
// 以下是附加的一些计算信息;
|
||||
int fileDataSize; // 文件音频数据大小;
|
||||
int fileHeaderSize; // 文件头大小;
|
||||
int fileTailSize; // 文件尾大小; 一般忽略。
|
||||
int fileTotalSize; // 文件总大小;
|
||||
|
||||
|
||||
// 理论上应该将所有数据初始化,这里只初始化可选的数据;
|
||||
WAVFILEHEADER() {
|
||||
fileTailSize = 8;
|
||||
memset ( RiffName, 0, 5 );
|
||||
memset ( WavName, 0, 5 );
|
||||
memset ( FmtName, 0, 5 );
|
||||
memset ( FactName, 0, 5 );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//44 固定的
|
||||
LIBQWAVSHARED_EXPORT bool addWavHeader ( QIODevice& outputDevice, const QAudioFormat& format );
|
||||
//8 固定的
|
||||
LIBQWAVSHARED_EXPORT bool addWavTail ( QIODevice& outputDevice );
|
||||
LIBQWAVSHARED_EXPORT bool addWavDataBytes ( QIODevice& outputDevice, const QByteArray& bytes );
|
||||
|
||||
|
||||
typedef struct _TWavFileInfo
|
||||
{
|
||||
int fileDataSize; // 文件音频数据大小;
|
||||
int fileHeaderSize; // 文件头大小;
|
||||
int fileTailSize; // 文件尾大小; 一般忽略。
|
||||
int fileTotalSize; // 文件总大小;
|
||||
} TWavFileInfo;
|
||||
|
||||
|
||||
LIBQWAVSHARED_EXPORT bool wavParse ( QString fileName, WAVFILEHEADER& WavFileHeader );
|
||||
LIBQWAVSHARED_EXPORT bool anlysisWavFileHeader ( QString fileName, QAudioFormat& format, TWavFileInfo& fileinfo );
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
||||
|
||||
#endif // LIBQWAV_H
|
18
src/multimedia/libqwav/libqwav_global.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef LIBQWAV_GLOBAL_H
|
||||
#define LIBQWAV_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#if defined(LIBQWAV_LIBRARY)
|
||||
# define LIBQWAVSHARED_EXPORT Q_DECL_EXPORT
|
||||
#elif defined(LIBQWAV_STATIC_LIBRARY)
|
||||
# define LIBQWAVSHARED_EXPORT
|
||||
#else
|
||||
# define LIBQWAVSHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
# define LIBQWAVSHARED_EXPORT
|
||||
#endif
|
||||
|
||||
#endif // LIBQWAV_GLOBAL_H
|
317
src/multimedia/qqtwavaudiomanager.cpp
Normal file
@ -0,0 +1,317 @@
|
||||
#include "qqtwavaudiomanager.h"
|
||||
#include "libqwav.h"
|
||||
|
||||
QQtWavAudioInput::QQtWavAudioInput ( QObject* parent ) : QObject ( parent )
|
||||
{
|
||||
mTimer = new QTimer ( this );
|
||||
connect ( mTimer, SIGNAL ( timeout() ), SLOT ( slotTimeout() ) );
|
||||
|
||||
mFileBytes.clear();
|
||||
mBytes.clear();
|
||||
mBytesBuffer.setBuffer ( &mBytes );
|
||||
|
||||
mTimerInterval = 20;
|
||||
}
|
||||
|
||||
QIODevice* QQtWavAudioInput::setSourceFile ( const QString& localFile )
|
||||
{
|
||||
//如果开着,不管。
|
||||
mSourceFile = localFile;
|
||||
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
//判断文件类型是否接受
|
||||
QMimeDatabase mimedb;
|
||||
QMimeType mimetype = mimedb.mimeTypeForFile ( mSourceFile );
|
||||
|
||||
if ( !QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) )
|
||||
{
|
||||
pline() << "filename" << localFile << "mimetype" << mimetype.name()
|
||||
<< QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) ;
|
||||
pline() << "can't play file";
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//判断音频具体格式
|
||||
//支持qrc文件
|
||||
TWavFileInfo info;
|
||||
bool ret = anlysisWavFileHeader ( mSourceFile, mFormat, info );
|
||||
//仅仅支持本地文件
|
||||
//bool ret = anlysisWavFileHeader_C ( localFile );
|
||||
|
||||
if ( !ret )
|
||||
{
|
||||
pline() << "wav format parse fail";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mFileTotalSize = info.fileTotalSize;
|
||||
mFileHeaderSize = info.fileHeaderSize;
|
||||
mFileDataSize = info.fileDataSize;
|
||||
mFileTailSize = info.fileTailSize;
|
||||
|
||||
return &mBytesBuffer;
|
||||
}
|
||||
|
||||
void QQtWavAudioInput::setTimerInterval ( int millSecond ) { mTimerInterval = millSecond; }
|
||||
|
||||
|
||||
void QQtWavAudioInput::start()
|
||||
{
|
||||
stop();
|
||||
|
||||
mChannelCount = mFormat.channelCount();
|
||||
mSampleSize = mFormat.sampleSize();
|
||||
mSampleRate = mFormat.sampleRate();
|
||||
|
||||
//读取到数据
|
||||
QFile f ( mSourceFile );
|
||||
f.open ( QFile::ReadOnly );
|
||||
QByteArray b = f.read ( mFileHeaderSize );
|
||||
//这个地方测试完成:内部解析wav头,两个都很成功。C Qt 都OK.
|
||||
//pline() << b;
|
||||
mFileBytes = f.read ( mFileDataSize );
|
||||
f.close();
|
||||
|
||||
mBytesBuffer.open ( QIODevice::ReadWrite );
|
||||
mTimer->start ( mTimerInterval );
|
||||
return;
|
||||
}
|
||||
|
||||
void QQtWavAudioInput::stop()
|
||||
{
|
||||
//如果正在播放,先关闭写入音频数据流。
|
||||
mTimer->stop();
|
||||
//如果存在,则清空。
|
||||
//这两个变量Buffer是什么操作关系?QBuffer是QByteArray的QIODevice套。
|
||||
//改变QByteArray,会直接影响QBuffer的读写。QBuffer也会影响QByteArray的内容。
|
||||
mFileBytes.clear();
|
||||
mBytes.clear();
|
||||
|
||||
if ( mBytesBuffer.isOpen() )
|
||||
mBytesBuffer.close();
|
||||
}
|
||||
|
||||
int QQtWavAudioInput::fileTotalSize() {return mFileTotalSize;}
|
||||
|
||||
int QQtWavAudioInput::fileHeaderSize() { return mFileHeaderSize; }
|
||||
|
||||
int QQtWavAudioInput::fileDataSize() {return mFileDataSize;}
|
||||
|
||||
int QQtWavAudioInput::fileTailSize() {return mFileTailSize;}
|
||||
|
||||
|
||||
void QQtWavAudioInput::slotTimeout()
|
||||
{
|
||||
//1s 字节数 = 采样率 * 采样深度(位宽)* 通道数 / 8
|
||||
//mTimerInterval ms 字节数 = 1s 字节数 / (1000/mTimerInterval)
|
||||
//每个音符 字节数 = 采样深度(位宽)* 通道数 / 8;
|
||||
int frameSize = mSampleRate * mSampleSize * mChannelCount / 8 / ( 1000 / mTimerInterval );
|
||||
QByteArray tempBytes;
|
||||
|
||||
if ( mFileBytes.size() > frameSize )
|
||||
{
|
||||
tempBytes.resize ( frameSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBytes.resize ( mFileBytes.size() );
|
||||
}
|
||||
|
||||
//pline() << mFileBytes.size() << tempBytes.size() << frameSize;
|
||||
//mFileBytes 逐渐减少
|
||||
mFileBytes >> tempBytes;
|
||||
//这是给用户的。
|
||||
mBytes = tempBytes;
|
||||
//回到初始位置
|
||||
mBytesBuffer.seek ( 0 );
|
||||
//激发readyRead信号
|
||||
mBytesBuffer.write ( 0 );
|
||||
|
||||
if ( mFileBytes.isEmpty() )
|
||||
{
|
||||
//pline() << mFileBytes.size() << 0 << frameSize;
|
||||
//这里不要关闭Buffer,客户一般还没用完。
|
||||
mTimer->stop();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QQtWavAudioOutput::QQtWavAudioOutput ( QObject* parent ) : QObject ( parent )
|
||||
{
|
||||
mFileBytes.clear();
|
||||
mBytesBuffer.setBuffer ( &mFileBytes );
|
||||
|
||||
mFormat.setByteOrder ( QAudioFormat::LittleEndian );
|
||||
mFormat.setChannelCount ( 2 );
|
||||
mFormat.setCodec ( "audio/pcm" );
|
||||
mFormat.setSampleRate ( 44100 );
|
||||
mFormat.setSampleSize ( 16 );
|
||||
mFormat.setSampleType ( QAudioFormat::SignedInt );
|
||||
}
|
||||
|
||||
QIODevice* QQtWavAudioOutput::setSourceFile ( const QString& localFile )
|
||||
{
|
||||
mSourceFile = localFile;
|
||||
return &mBytesBuffer;
|
||||
}
|
||||
|
||||
QAudioFormat& QQtWavAudioOutput::format() { return mFormat; }
|
||||
|
||||
void QQtWavAudioOutput::start()
|
||||
{
|
||||
if ( mSourceFile.isEmpty() )
|
||||
return;
|
||||
|
||||
//这里清空文件,不会发生保存?不会,这里清空Buffer。
|
||||
mFileBytes.clear();
|
||||
|
||||
if ( mBytesBuffer.isOpen() )
|
||||
mBytesBuffer.close();
|
||||
|
||||
mBytesBuffer.open ( QIODevice::WriteOnly );
|
||||
}
|
||||
|
||||
void QQtWavAudioOutput::stop()
|
||||
{
|
||||
//在stop的时候,才会把数据全部存储到wav文件
|
||||
if ( mSourceFile.isEmpty() )
|
||||
return;
|
||||
|
||||
//防止多次关闭导致音频文件被破坏。
|
||||
if ( mFileBytes.isEmpty() )
|
||||
return;
|
||||
|
||||
QFile file ( mSourceFile );
|
||||
file.open ( QFile::Truncate | QFile::WriteOnly );
|
||||
|
||||
addWavHeader ( file, mFormat );
|
||||
file.write ( mFileBytes );
|
||||
addWavTail ( file );
|
||||
//这个时候,Header里面RiffLength是错误的。改写
|
||||
file.seek ( 0 );
|
||||
addWavHeader ( file, mFormat );
|
||||
//现在纠正好了。
|
||||
file.close();
|
||||
|
||||
mFileBytes.clear();
|
||||
|
||||
if ( mBytesBuffer.isOpen() )
|
||||
mBytesBuffer.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
QQtWavAudioManager::QQtWavAudioManager ( QObject* parent ) : QObject ( parent )
|
||||
{
|
||||
mInputManager = new QQtWavAudioInput ( this );
|
||||
mOutputManager = new QQtWavAudioOutput ( this );
|
||||
|
||||
mInputDevice = mInputManager->device();
|
||||
mOutputDevice = mOutputManager->device();
|
||||
|
||||
connect ( mInputDevice, SIGNAL ( readyRead() ),
|
||||
this, SIGNAL ( readyRead() ) );
|
||||
|
||||
}
|
||||
|
||||
QQtWavAudioManager::~QQtWavAudioManager()
|
||||
{
|
||||
stopInput();
|
||||
stopOutput();
|
||||
}
|
||||
|
||||
void QQtWavAudioManager::setInputSourceFile ( const QString& localFile )
|
||||
{
|
||||
QIODevice* ioDev = mInputManager->setSourceFile ( localFile );
|
||||
|
||||
if ( !ioDev )
|
||||
{
|
||||
pline() << mInputManager->sourceFile()
|
||||
<< inputAudioFormat().sampleSize()
|
||||
<< inputAudioFormat().sampleRate()
|
||||
<< inputAudioFormat().channelCount()
|
||||
<< "open failed, errcode:"
|
||||
<< "-1";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString QQtWavAudioManager::inputSourceFile() { return mInputManager->sourceFile(); }
|
||||
|
||||
void QQtWavAudioManager::setOutputSourceFile ( const QString& localFile )
|
||||
{
|
||||
QIODevice* ioDev = mOutputManager->setSourceFile ( localFile );
|
||||
|
||||
if ( !ioDev )
|
||||
{
|
||||
pline() << mOutputManager->sourceFile()
|
||||
<< outputAudioFormat().sampleSize()
|
||||
<< outputAudioFormat().sampleRate()
|
||||
<< outputAudioFormat().channelCount()
|
||||
<< "open failed, errcode:"
|
||||
<< "-1";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString QQtWavAudioManager::outputSourceFile() { return mOutputManager->sourceFile(); }
|
||||
|
||||
const QAudioFormat& QQtWavAudioManager::inputAudioFormat() { return mInputManager->format(); }
|
||||
|
||||
QAudioFormat& QQtWavAudioManager::outputAudioFormat() { return mOutputManager->format(); }
|
||||
|
||||
int QQtWavAudioManager::inputFileTotalSize() { return mInputManager->fileTotalSize(); }
|
||||
|
||||
int QQtWavAudioManager::inputFileHeaderSize() { return mInputManager->fileHeaderSize(); }
|
||||
|
||||
int QQtWavAudioManager::inputFileDataSize() { return mInputManager->fileDataSize(); }
|
||||
|
||||
int QQtWavAudioManager::inputFileTailSize() { return mInputManager->fileTailSize(); }
|
||||
|
||||
QQtWavAudioInput* QQtWavAudioManager::inputManager() { return mInputManager; }
|
||||
|
||||
QIODevice* QQtWavAudioManager::inputDevice() { return mInputDevice; }
|
||||
|
||||
QQtWavAudioOutput* QQtWavAudioManager::outputManager() { return mOutputManager; }
|
||||
|
||||
QIODevice* QQtWavAudioManager::outputDevice() { return mOutputDevice; }
|
||||
|
||||
void QQtWavAudioManager::startInput()
|
||||
{
|
||||
stopInput();
|
||||
mInputManager->start();
|
||||
}
|
||||
|
||||
void QQtWavAudioManager::stopInput()
|
||||
{
|
||||
mInputManager->stop();
|
||||
}
|
||||
|
||||
void QQtWavAudioManager::startOutput()
|
||||
{
|
||||
stopOutput();
|
||||
mOutputManager->start();
|
||||
}
|
||||
|
||||
void QQtWavAudioManager::stopOutput()
|
||||
{
|
||||
mOutputManager->stop();
|
||||
}
|
||||
|
||||
QByteArray QQtWavAudioManager::readAll()
|
||||
{
|
||||
return mInputDevice->readAll();
|
||||
}
|
||||
|
||||
QByteArray QQtWavAudioManager::read ( qint64 maxlen )
|
||||
{
|
||||
return mInputDevice->read ( maxlen );
|
||||
}
|
||||
|
||||
void QQtWavAudioManager::write ( const QByteArray& bytes )
|
||||
{
|
||||
mOutputDevice->write ( bytes );
|
||||
}
|
220
src/multimedia/qqtwavaudiomanager.h
Normal file
@ -0,0 +1,220 @@
|
||||
#ifndef QQTWAVAUDIOMANAGER_H
|
||||
#define QQTWAVAUDIOMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qqtcore.h>
|
||||
#include <qqt-local.h>
|
||||
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
|
||||
#include <QMimeType>
|
||||
#include <QMimeData>
|
||||
#include <QMimeDatabase>
|
||||
|
||||
#include <QSound>
|
||||
#include <QSoundEffect>
|
||||
#endif
|
||||
|
||||
#include <qqtaudiomanager.h>
|
||||
|
||||
//设计思路:QQtWavAudioInput和QQtWavAudioOutput两边都是内存和wav文件,为内存服务。
|
||||
|
||||
/**
|
||||
* @brief The QQtWavAudioInput class
|
||||
* QQtWavAudioInput具备QAudioInput的能力,可以把wav文件的音频帧,通过readyRead输出。
|
||||
* 每次/10ms一帧,通过QIODevice readyRead发射给用户。
|
||||
* 升级目标:QQtAudioInput里支持的设备比较广泛,文件类型比较多。
|
||||
*
|
||||
* 原理,设置Sourcefile,返回QIODevice,进行读取。一次加载,逐渐读取。
|
||||
*
|
||||
* 不要使用大文件。
|
||||
* Qt 中有一个 QBuffer 类,可以将 QByteArray 包装成一个 QIODevice。QMemIODevice = QBuffer
|
||||
* 如果来的是个QByteArray,那么,用QBuffer封装,
|
||||
* 在 open 函数中调用 QIODevice::open(mode)
|
||||
* 要解析wav,用自定义程序,还是用开源Library(libsndfile)?自定义程序
|
||||
* 要播放wav,是用wav的音频格式来设定输出设备,还是用个输出设备支持的音频格式,wav里选取进行使用?使用wav的。
|
||||
*
|
||||
* 尝试用QAudioDecoder,解码器不支持x-wav,defaultServiceProvider::requestService(): no service found for - "org.qt-project.qt.audiodecode"
|
||||
* 为什么QSoundEffect支持那么多wav格式?("audio/x-wav", "audio/wav", "audio/wave", "audio/x-pn-wav")
|
||||
* LibQQt库
|
||||
* QAudioDecoder保存了一个提交,#5643241
|
||||
* QWavAudioEffect保存了一个提交,#5f43622
|
||||
*/
|
||||
class QQTSHARED_EXPORT QQtWavAudioInput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QQtWavAudioInput ( QObject* parent = nullptr );
|
||||
//自动解析格式,和文件大小
|
||||
QIODevice* setSourceFile ( const QString& localFile );
|
||||
QString sourceFile() { return mSourceFile; }
|
||||
|
||||
//读取用。这个是个内部公用的,并不是临时的。碰巧了。
|
||||
QIODevice* device() { return &mBytesBuffer; }
|
||||
|
||||
//设置读文件的时钟快慢(硬盘快,时钟快,每次读的少;硬盘慢,时钟慢,每次读的多)
|
||||
//采样间隔 10-100ms default: macOS SSD 20 ms
|
||||
//windows 机械硬盘 100ms, windows 机械硬盘 is slower than macOS SSD.
|
||||
int timerInterval() const { return mTimerInterval; }
|
||||
void setTimerInterval ( int millSecond = 20 );
|
||||
//可以频繁开启,tip:用完一定要关闭,系统会自动关闭。
|
||||
//已经检查测试,没有文件设备漏开关问题。
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
//每次修改SourceFile,这些都会改变。在不改变SourceFile的时候是内部使用的值。
|
||||
const QAudioFormat& format() { return mFormat; }
|
||||
int fileTotalSize();
|
||||
int fileHeaderSize();
|
||||
int fileDataSize();
|
||||
int fileTailSize();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
void slotTimeout();
|
||||
|
||||
private:
|
||||
QString mSourceFile;
|
||||
//用于保存文件全部Bytes
|
||||
QByteArray mFileBytes;
|
||||
//用于和Buffer联系,给用户提供每次读取的帧。
|
||||
QByteArray mBytes;
|
||||
QBuffer mBytesBuffer;
|
||||
|
||||
//每次设置新Source,会改变这些值。
|
||||
QAudioFormat mFormat;
|
||||
int mFileDataSize;
|
||||
int mFileHeaderSize;
|
||||
int mFileTailSize;
|
||||
int mFileTotalSize;
|
||||
//这三个不准公开出来啊。
|
||||
int mSampleRate;
|
||||
int mSampleSize;
|
||||
int mChannelCount;
|
||||
|
||||
QTimer* mTimer;
|
||||
int mTimerInterval;
|
||||
|
||||
public:
|
||||
protected:
|
||||
|
||||
public:
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
class QQTSHARED_EXPORT QQtWavAudioOutput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QQtWavAudioOutput ( QObject* parent = nullptr );
|
||||
|
||||
QIODevice* setSourceFile ( const QString& localFile );
|
||||
QString sourceFile() { return mSourceFile; }
|
||||
|
||||
//写入用
|
||||
QIODevice* device() { return &mBytesBuffer; }
|
||||
|
||||
//用户务必设置format,默认值为2 16 44100
|
||||
QAudioFormat& format();
|
||||
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
QString mSourceFile;
|
||||
QAudioFormat mFormat;
|
||||
|
||||
QBuffer mBytesBuffer;
|
||||
QByteArray mFileBytes;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The QQtWavAudioManager class
|
||||
* Wav媒体音频管理器
|
||||
*
|
||||
* 这个Wav音频管理器目标为用户提供Wav媒体的音频数据帧,附加音频数据帧输出到Wav媒体的功能。
|
||||
*/
|
||||
class QQTSHARED_EXPORT QQtWavAudioManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QQtWavAudioManager ( QObject* parent = nullptr );
|
||||
|
||||
~QQtWavAudioManager();
|
||||
|
||||
/**
|
||||
* 选择输入、输出Wav媒体
|
||||
*/
|
||||
//设置输入或者输出wav文件
|
||||
void setInputSourceFile ( const QString& localFile );
|
||||
QString inputSourceFile();
|
||||
void setOutputSourceFile ( const QString& localFile );
|
||||
QString outputSourceFile();
|
||||
|
||||
/**
|
||||
* 选择音频流的格式
|
||||
*/
|
||||
|
||||
//获取输入文件的音频流格式
|
||||
const QAudioFormat& inputAudioFormat();
|
||||
//设置输出音频流的音频格式,输出保存的时候使用。
|
||||
QAudioFormat& outputAudioFormat();
|
||||
|
||||
//每次修改SourceFile,这些都会改变。
|
||||
int inputFileTotalSize();
|
||||
int inputFileHeaderSize();
|
||||
int inputFileDataSize();
|
||||
int inputFileTailSize();
|
||||
|
||||
|
||||
/**
|
||||
* 操作输入、输出Wav媒体
|
||||
*/
|
||||
|
||||
QQtWavAudioInput* inputManager();
|
||||
//如果输入,从这里读取帧
|
||||
QIODevice* inputDevice();
|
||||
|
||||
QQtWavAudioOutput* outputManager();
|
||||
//如果输出,从这里写入帧,提前设置好格式哦...
|
||||
QIODevice* outputDevice();
|
||||
|
||||
void startInput();
|
||||
void stopInput();
|
||||
|
||||
void startOutput();
|
||||
void stopOutput();
|
||||
|
||||
//这两个是方便函数,一般都用这几个进行读写,不使用上边的。
|
||||
QByteArray readAll();
|
||||
QByteArray read ( qint64 maxlen );
|
||||
void write ( const QByteArray& bytes );
|
||||
|
||||
signals:
|
||||
/*音频数据准备就绪,readAll即可读取。*/
|
||||
void readyRead();
|
||||
public slots:
|
||||
|
||||
private:
|
||||
|
||||
QQtWavAudioInput* mInputManager;
|
||||
QQtWavAudioOutput* mOutputManager;
|
||||
|
||||
QIODevice* mInputDevice;
|
||||
QIODevice* mOutputDevice;
|
||||
|
||||
//这三个不准公开出来。
|
||||
int mSampleRate;
|
||||
int mSampleSize;
|
||||
int mChannelCount;
|
||||
};
|
||||
|
||||
#endif // QQTWAVAUDIOMANAGER_H
|
163
src/multimedia/qqtwavsoundeffect.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
#include "qqtwavsoundeffect.h"
|
||||
|
||||
|
||||
QQtWavSoundEffect* QQtWavSoundEffect::msInstance = NULL;
|
||||
|
||||
QQtWavSoundEffect* QQtWavSoundEffect::Instance ( QObject* parent )
|
||||
{
|
||||
if ( !msInstance )
|
||||
msInstance = new QQtWavSoundEffect ( parent );
|
||||
|
||||
return msInstance;
|
||||
}
|
||||
|
||||
QQtWavSoundEffect::QQtWavSoundEffect ( QObject* parent ) : QObject ( parent )
|
||||
{
|
||||
mVolume = 1;
|
||||
mIOInput = NULL;
|
||||
mLooping = 1;
|
||||
mLoops = 1;
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::setOutputDevice ( const QAudioDeviceInfo& output )
|
||||
{
|
||||
if ( output.isNull() )
|
||||
manager.outputDeviceInfo() = QQtAudioManager::defaultOutputDevice();
|
||||
else
|
||||
manager.outputDeviceInfo() = output;
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::useDefaultOutputDevice()
|
||||
{
|
||||
manager.outputDeviceInfo() = QQtAudioManager::defaultOutputDevice();
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::useCustomOutputDevice ( const QAudioDeviceInfo& output )
|
||||
{
|
||||
manager.outputDeviceInfo() = output;
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
QDebug& operator << ( QDebug& dbg, const QAudioFormat& fmt )
|
||||
{
|
||||
return dbg;
|
||||
}
|
||||
#endif
|
||||
|
||||
void QQtWavSoundEffect::play ( QString localFile )
|
||||
{
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
//判断文件类型是否接受
|
||||
QMimeDatabase mimedb;
|
||||
QMimeType mimetype = mimedb.mimeTypeForFile ( localFile );
|
||||
|
||||
if ( !QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) )
|
||||
{
|
||||
pline() << "filename" << localFile << "mimetype" << mimetype.name()
|
||||
<< QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) ;
|
||||
pline() << "can't play file";
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
mSourceFile = localFile;
|
||||
|
||||
stop();
|
||||
|
||||
mIOInput = mWavInput.setSourceFile ( localFile );
|
||||
connect ( mIOInput, SIGNAL ( readyRead() ),
|
||||
this, SLOT ( readyRead() ) );
|
||||
|
||||
QAudioDeviceInfo& usingOutput = manager.outputDeviceInfo();
|
||||
|
||||
QAudioFormat fmt = mWavInput.format();
|
||||
|
||||
//输出设备是否支持格式是否支持
|
||||
if ( !usingOutput.isFormatSupported ( fmt ) )
|
||||
{
|
||||
//当前使用设备是否支持
|
||||
pline() << "output cant support" << fmt;
|
||||
fmt = usingOutput.nearestFormat ( fmt ); //转换为最接近格式
|
||||
pline() << "use format" << fmt;
|
||||
}
|
||||
|
||||
manager.outputAudioFormat() = fmt;
|
||||
|
||||
manager.startOutput();
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
//默认是静音的。
|
||||
manager.outputManager()->setVolume ( mVolume );
|
||||
#endif
|
||||
|
||||
//不响,音频输出设备接受顺序的间隔的输出,不接受一股脑输出。
|
||||
//manager.write ( bytes );
|
||||
//OK, 达到QSound效果。
|
||||
mWavInput.start();
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::stop()
|
||||
{
|
||||
//如果正在播放,先关闭
|
||||
if ( mIOInput )
|
||||
{
|
||||
mWavInput.stop();
|
||||
manager.stopOutput();
|
||||
disconnect ( mIOInput, SIGNAL ( readyRead() ),
|
||||
this, SLOT ( readyRead() ) );
|
||||
mIOInput = NULL;
|
||||
}
|
||||
|
||||
mLooping = 1;
|
||||
mDataSize = 0;
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::setVolume ( qreal volume )
|
||||
{
|
||||
mVolume = volume;
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
manager.outputManager()->setVolume ( mVolume );
|
||||
#endif
|
||||
}
|
||||
|
||||
int QQtWavSoundEffect::loops() const { return mLoops; }
|
||||
|
||||
int QQtWavSoundEffect::loopsRemaining() const
|
||||
{
|
||||
return mLoops - mLooping;
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::setLoops ( int loops )
|
||||
{
|
||||
mLoops = loops;
|
||||
}
|
||||
|
||||
void QQtWavSoundEffect::readyRead()
|
||||
{
|
||||
QByteArray bytes = mIOInput->readAll();
|
||||
//pline() << bytes.size();
|
||||
manager.write ( bytes );
|
||||
|
||||
mDataSize += bytes.size();
|
||||
|
||||
if ( mDataSize == mWavInput.fileDataSize() )
|
||||
{
|
||||
int loop = mLooping;
|
||||
|
||||
if ( loop < loops() )
|
||||
play ( mSourceFile );
|
||||
|
||||
mLooping = loop + 1;
|
||||
}
|
||||
}
|
||||
|
||||
QQtWavSoundEffect* QQtWavSound ( QString localFile )
|
||||
{
|
||||
if ( !localFile.isEmpty() )
|
||||
QQtWavSoundEffect::Instance ( )->play ( localFile );
|
||||
|
||||
return QQtWavSoundEffect::Instance();
|
||||
}
|
||||
|
80
src/multimedia/qqtwavsoundeffect.h
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef QQTAUDIOEFFECT_H
|
||||
#define QQTAUDIOEFFECT_H
|
||||
|
||||
|
||||
#include <qqtwavaudiomanager.h>
|
||||
|
||||
#include <qqtcore.h>
|
||||
#include <qqt-local.h>
|
||||
/*
|
||||
* QQtWavSoundEffect = QSoundEffect + QSound +...
|
||||
* QQtWavSoundEffect支持从wav获取声音并输出,弥补QSoundEffect(+他的高级点的封装QSound)不能支持选择设备的缺失。
|
||||
* QQtWavSoundEffect默认使用默认输出设备。
|
||||
*/
|
||||
class QQTSHARED_EXPORT QQtWavSoundEffect : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//这样做的目的,在于使用一个实例去播放音效。
|
||||
//如果是个临时变量,函数执行返回了,但是还没播放完,甚至还没来得及开始呢,这时,播放不出来的。
|
||||
static QQtWavSoundEffect* Instance ( QObject* parent = nullptr );
|
||||
|
||||
explicit QQtWavSoundEffect ( QObject* parent = nullptr );
|
||||
~QQtWavSoundEffect() {
|
||||
stop();
|
||||
}
|
||||
|
||||
//设置设备以后,不需要每次都设置
|
||||
//更换设备不会引发播放更改,只会更改内部设备记录。调用play才会导致播放更改。
|
||||
void setOutputDevice ( const QAudioDeviceInfo& output = QAudioDeviceInfo() );
|
||||
|
||||
void useDefaultOutputDevice();
|
||||
|
||||
void useCustomOutputDevice ( const QAudioDeviceInfo& output );
|
||||
|
||||
void play ( QString localFile );
|
||||
|
||||
void stop();
|
||||
|
||||
//设置声音以后,不需要每次都要设置。
|
||||
void setVolume ( qreal volume );
|
||||
|
||||
//设置loop会保存下来,不需要每次设置。
|
||||
int loops() const;
|
||||
int loopsRemaining() const;
|
||||
void setLoops ( int loops );
|
||||
|
||||
//设置读文件的时钟快慢(硬盘快,时钟快,每次读的少;硬盘慢,时钟慢,每次读的多)
|
||||
//默认使用 macOS SSD 20ms
|
||||
//Windows上,机械硬盘,可能会延迟,可以设置100ms。
|
||||
void setTimerInterval ( int millSecond = 20 ) {
|
||||
mWavInput.setTimerInterval ( millSecond );
|
||||
}
|
||||
|
||||
private slots:
|
||||
void readyRead();
|
||||
|
||||
private:
|
||||
//不需要额外初始化的地方
|
||||
//mingw32 5.3 静态成员不准导出?作为静态类这块编译出现错误
|
||||
//error: definition of static data member 'QQtWavSoundEffect::msInstance' of dllimport'd class
|
||||
//这个已经查出来了,在qqt_header.pri有一个WIN64的宏缺失,导致QQT_STATIC_LIBRARY缺失,引发QQt在QQTSHAREDEXPORT=import下编译,所以引发这个变量重新定义的错误,而报错是在导入的类里面定义了静态成员,也就是说导入类不准许静态成员的定义初始化代码出现,引入类的静态成员在自己的实现文件里出现了定义。变量重定义了。
|
||||
static QQtWavSoundEffect* msInstance;
|
||||
|
||||
QQtWavAudioInput mWavInput;
|
||||
QIODevice* mIOInput;
|
||||
QQtAudioManager manager;
|
||||
QString mSourceFile;
|
||||
int mDataSize;
|
||||
//volume会被记住。
|
||||
qreal mVolume;
|
||||
int mLoops;
|
||||
int mLooping;
|
||||
};
|
||||
|
||||
//在使用QQtWavSound等函数之前,调用类的instance函数,+parent 初始化一下实例。
|
||||
//=QSound::play()
|
||||
QQTSHARED_EXPORT QQtWavSoundEffect* QQtWavSound ( QString localFile = "" );
|
||||
|
||||
#endif // QQTAUDIOEFFECT_H
|
BIN
test/voicetest2/AppRoot/res/9612.wav
Normal file
BIN
test/voicetest2/AppRoot/res/9733.wav
Normal file
BIN
test/voicetest2/AppRoot/res/9763.wav
Normal file
BIN
test/voicetest2/AppRoot/res/9767.wav
Normal file
99
test/voicetest2/android/AndroidManifest.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.qtproject.example.voicetest2" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="voicetest2" android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="声音设备2" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
<!-- Application arguments -->
|
||||
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||
<!-- Application arguments -->
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="voicetest2"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
<!-- Deploy Qt libs as part of package -->
|
||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
||||
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
|
||||
<!-- Run with local libs -->
|
||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||
<!-- Messages maps -->
|
||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
<!-- Messages maps -->
|
||||
|
||||
<!-- Splash screen -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||
<!-- Splash screen -->
|
||||
|
||||
<!-- Background running -->
|
||||
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||
application still try to draw after
|
||||
"applicationStateChanged(Qt::ApplicationSuspended)"
|
||||
signal is sent! -->
|
||||
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||
<!-- Background running -->
|
||||
|
||||
<!-- auto screen scale factor -->
|
||||
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||
<!-- auto screen scale factor -->
|
||||
|
||||
<!-- extract android style -->
|
||||
<!-- available android:values :
|
||||
* full - useful QWidget & Quick Controls 1 apps
|
||||
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
|
||||
* none - useful for apps that don't use any of the above Qt modules
|
||||
-->
|
||||
<meta-data android:name="android.app.extract_android_style" android:value="full"/>
|
||||
<!-- extract android style -->
|
||||
</activity>
|
||||
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/>
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
|
||||
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
<uses-permission android:name="android.permission.CALL_PHONE"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SOCIAL_STREAM"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.CALL_PRIVILEGED"/>
|
||||
<uses-permission android:name="android.permission.FORCE_BACK"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.NFC"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.READ_INPUT_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"/>
|
||||
<uses-permission android:name="android.permission.DEVICE_POWER"/>
|
||||
<uses-permission android:name="android.permission.SET_DEBUG_APP"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.SET_ORIENTATION"/>
|
||||
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY"/>
|
||||
</manifest>
|
BIN
test/voicetest2/android/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
test/voicetest2/android/res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
test/voicetest2/android/res/drawable-ldpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 964 B |
BIN
test/voicetest2/android/res/drawable-ldpi/icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
test/voicetest2/android/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
test/voicetest2/android/res/drawable-mdpi/icon.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
test/voicetest2/android/res/drawable-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
test/voicetest2/android/res/drawable-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
test/voicetest2/android/res/drawable-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
18
test/voicetest2/main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QQtApplication>
|
||||
#include <qqtwidgets.h>
|
||||
#include <qqtapplication.h>
|
||||
|
||||
int main ( int argc, char* argv[] )
|
||||
{
|
||||
QQtApplication a ( argc, argv );
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
w.showMaximized();
|
||||
#endif
|
||||
|
||||
return a.exec();
|
||||
}
|
561
test/voicetest2/mainwindow.cpp
Normal file
@ -0,0 +1,561 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include <qqtaudiomanager.h>
|
||||
#include <qqtcore.h>
|
||||
#include <qsound.h>
|
||||
#include <qsoundeffect.h>
|
||||
#include <qqtsoundeffect.h>
|
||||
#include <qqtframe.h>
|
||||
|
||||
MainWindow::MainWindow ( QWidget* parent ) :
|
||||
QMainWindow ( parent ),
|
||||
ui ( new Ui::MainWindow )
|
||||
{
|
||||
ui->setupUi ( this );
|
||||
|
||||
connect ( &manager, SIGNAL ( readyRead() ), this, SLOT ( readyRead() ) );
|
||||
|
||||
connect ( &wavRecManager, SIGNAL ( readyRead() ), this, SLOT ( wavRecReadyRead() ) );
|
||||
connect ( &wavFileManager, SIGNAL ( readyRead() ), this, SLOT ( wavFileReadyRead() ) );
|
||||
|
||||
QList<QAudioDeviceInfo> ladInfo;
|
||||
ladInfo = QAudioDeviceInfo::availableDevices ( QAudio::AudioInput );
|
||||
QListIterator<QAudioDeviceInfo> itor ( ladInfo );
|
||||
pline() << "本机音频输入设备列表";
|
||||
|
||||
while ( itor.hasNext() )
|
||||
pline() << itor.next().deviceName();
|
||||
|
||||
pline() << "默认输入设备" << QAudioDeviceInfo::defaultInputDevice().deviceName();
|
||||
pline() << "输入设备详细信息";
|
||||
itor.toFront();
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QAudioDeviceInfo adInfo = itor.next();
|
||||
pline() << adInfo.deviceName();
|
||||
pline() << adInfo.supportedByteOrders();
|
||||
pline() << adInfo.supportedChannelCounts();
|
||||
pline() << adInfo.supportedCodecs();
|
||||
pline() << adInfo.supportedSampleRates();
|
||||
pline() << adInfo.supportedSampleSizes();
|
||||
pline() << adInfo.supportedSampleTypes();
|
||||
}
|
||||
|
||||
|
||||
QList<QAudioDeviceInfo> ladOutputInfo;
|
||||
ladOutputInfo = QAudioDeviceInfo::availableDevices ( QAudio::AudioOutput );
|
||||
QListIterator<QAudioDeviceInfo> itor2 ( ladOutputInfo );
|
||||
pline() << "本机音频输出设备列表";
|
||||
|
||||
while ( itor2.hasNext() )
|
||||
pline() << itor2.next().deviceName();
|
||||
|
||||
pline() << "默认输出设备" << QAudioDeviceInfo::defaultOutputDevice().deviceName();
|
||||
pline() << "输出设备详细信息";
|
||||
itor2.toFront();
|
||||
|
||||
while ( itor2.hasNext() )
|
||||
{
|
||||
QAudioDeviceInfo adInfo = itor2.next();
|
||||
pline() << adInfo.deviceName();
|
||||
pline() << adInfo.supportedByteOrders();
|
||||
pline() << adInfo.supportedChannelCounts();
|
||||
pline() << adInfo.supportedCodecs();
|
||||
pline() << adInfo.supportedSampleRates();
|
||||
pline() << adInfo.supportedSampleSizes();
|
||||
pline() << adInfo.supportedSampleTypes();
|
||||
}
|
||||
|
||||
|
||||
pline() << "..........................";
|
||||
|
||||
connect ( ui->inputListWidget->selectionModel(), SIGNAL ( currentRowChanged ( QModelIndex, QModelIndex ) ),
|
||||
this, SLOT ( currentInputRowChanged ( QModelIndex, QModelIndex ) ) );
|
||||
connect ( ui->outputListWidget->selectionModel(), SIGNAL ( currentRowChanged ( QModelIndex, QModelIndex ) ),
|
||||
this, SLOT ( currentOutputRowChanged ( QModelIndex, QModelIndex ) ) );
|
||||
|
||||
// on_pushButton_2_clicked();
|
||||
// ui->inputListWidget->setCurrentRow ( 0 );
|
||||
// ui->outputListWidget->setCurrentRow ( 0 );
|
||||
// ui->inputListWidget->setFocus();
|
||||
|
||||
ui->inHS->setRange ( 0, 100 );
|
||||
ui->inHS->setValue ( 100 );
|
||||
|
||||
ui->outHS->setRange ( 0, 100 );
|
||||
ui->outHS->setValue ( 100 );
|
||||
|
||||
//pline() << QSoundEffect::supportedMimeTypes();
|
||||
|
||||
QSoundEffect e;
|
||||
e.setLoopCount ( 1 );
|
||||
e.setVolume ( 0.9f );
|
||||
e.setMuted ( false );
|
||||
|
||||
//不响
|
||||
QUrl u;
|
||||
u.setUrl ( "http://xmdx.sc.chinaz.com/Files/DownLoad/sound1/201802/9733.wav" );
|
||||
e.setSource ( u );
|
||||
//e.play();
|
||||
|
||||
//响
|
||||
e.setSource ( QUrl::fromLocalFile ( conf_res ( "9733.wav" ) ) );
|
||||
//e.play();
|
||||
|
||||
//响
|
||||
//QSound::play ( conf_res ( "9733.wav" ) );
|
||||
|
||||
//响
|
||||
QQtWavSoundEffect e1;
|
||||
//e1.play ( conf_res ( "9733.wav" ) );
|
||||
|
||||
//响
|
||||
//QApplication::beep();
|
||||
|
||||
//建议初始化
|
||||
QQtWavSoundEffect::Instance ( this );
|
||||
|
||||
//可以多次循环调用。
|
||||
QQtWavSound ( conf_res ( "9733.wav" ) );
|
||||
|
||||
//QQtSleep ( 3000 );
|
||||
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QAudioDeviceInfo MainWindow::findInputAudioDeviceInfoByName ( QString devName )
|
||||
{
|
||||
QList<QAudioDeviceInfo> ladInfo;
|
||||
ladInfo = QQtAudioManager::availableInputDevices();
|
||||
QListIterator<QAudioDeviceInfo> itor ( ladInfo );
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QAudioDeviceInfo adInfo = itor.next();
|
||||
|
||||
if ( devName == adInfo.deviceName() )
|
||||
return adInfo;
|
||||
}
|
||||
}
|
||||
|
||||
QAudioDeviceInfo MainWindow::findOutputAudioDeviceInfoByName ( QString devName )
|
||||
{
|
||||
QList<QAudioDeviceInfo> ladInfo;
|
||||
ladInfo = QQtAudioManager::availableOutputDevices();
|
||||
QListIterator<QAudioDeviceInfo> itor ( ladInfo );
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QAudioDeviceInfo adInfo = itor.next();
|
||||
|
||||
if ( devName == adInfo.deviceName() )
|
||||
return adInfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_pushButton_2_clicked()
|
||||
{
|
||||
ui->inputListWidget->clear();
|
||||
|
||||
QList<QAudioDeviceInfo> ladInfo;
|
||||
ladInfo = QQtAudioManager::availableInputDevices();
|
||||
QListIterator<QAudioDeviceInfo> itor ( ladInfo );
|
||||
pline() << "本机音频输入设备列表";
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QAudioDeviceInfo adInfo = itor.next();
|
||||
pline() << adInfo.deviceName();
|
||||
ui->inputListWidget->addItem ( adInfo.deviceName() );
|
||||
}
|
||||
|
||||
|
||||
ui->outputListWidget->clear();
|
||||
|
||||
QList<QAudioDeviceInfo> ladOutputInfo;
|
||||
ladOutputInfo = QQtAudioManager::availableOutputDevices();
|
||||
QListIterator<QAudioDeviceInfo> itor2 ( ladOutputInfo );
|
||||
pline() << "本机音频输出设备列表";
|
||||
|
||||
while ( itor2.hasNext() )
|
||||
{
|
||||
QAudioDeviceInfo adInfo = itor2.next();
|
||||
pline() << adInfo.deviceName();
|
||||
ui->outputListWidget->addItem ( adInfo.deviceName() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::currentInputRowChanged ( QModelIndex cur, QModelIndex )
|
||||
{
|
||||
/*在清空设备列表时,clear函数,会调用多次这个函数。在这里用cur valid加以过滤,否则,程序会崩溃退出。*/
|
||||
if ( !cur.isValid() )
|
||||
return;
|
||||
|
||||
ui->inBit->clear();
|
||||
ui->inChn->clear();
|
||||
ui->intRate->clear();
|
||||
|
||||
|
||||
QString name = cur.data().toString();
|
||||
QAudioDeviceInfo dev = findInputAudioDeviceInfoByName ( name );
|
||||
|
||||
if ( dev.isNull() )
|
||||
return;
|
||||
|
||||
QList<int> size = dev.supportedSampleSizes();
|
||||
QListIterator<int> itor ( size );
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QString s0 = QString::number ( itor.next() );
|
||||
ui->inBit->addItem ( s0 );
|
||||
}
|
||||
|
||||
itor = dev.supportedChannelCounts();
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QString s0 = QString::number ( itor.next() );
|
||||
ui->inChn->addItem ( s0 );
|
||||
}
|
||||
|
||||
itor = dev.supportedSampleRates();
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QString s0 = QString::number ( itor.next() );
|
||||
ui->intRate->addItem ( s0 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::currentOutputRowChanged ( QModelIndex cur, QModelIndex )
|
||||
{
|
||||
if ( !cur.isValid() )
|
||||
return;
|
||||
|
||||
ui->outBit->clear();
|
||||
ui->outChn->clear();
|
||||
ui->outRate->clear();
|
||||
|
||||
|
||||
QString name = cur.data().toString();
|
||||
QAudioDeviceInfo dev = findOutputAudioDeviceInfoByName ( name );
|
||||
|
||||
if ( dev.isNull() )
|
||||
return;
|
||||
|
||||
QList<int> size = dev.supportedSampleSizes();
|
||||
QListIterator<int> itor ( size );
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QString s0 = QString::number ( itor.next() );
|
||||
ui->outBit->addItem ( s0 );
|
||||
}
|
||||
|
||||
itor = dev.supportedChannelCounts();
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QString s0 = QString::number ( itor.next() );
|
||||
ui->outChn->addItem ( s0 );
|
||||
}
|
||||
|
||||
itor = dev.supportedSampleRates();
|
||||
|
||||
while ( itor.hasNext() )
|
||||
{
|
||||
QString s0 = QString::number ( itor.next() );
|
||||
ui->outRate->addItem ( s0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 处理声音三要点
|
||||
* 声音的格式 ,也就是声音三要素,输入一个、输出一个,manager对其分开管理,但是建议用户合并为一个置等。通道数、采样位宽、采样率
|
||||
* 声音设备 ,输入一个、输出一个,manager管理start\stop等接口,manager内部的inputManager和outputManager负责其他接口。
|
||||
* 声音设备的读写出入口 ,manager管理,包括可读信号和写入函数。
|
||||
*/
|
||||
void MainWindow::on_pushButton_clicked()
|
||||
{
|
||||
/*这里是自定义输入、输出设备*/
|
||||
QString name = QQtAudioManager::defaultInputDevice().deviceName();
|
||||
|
||||
if ( ui->inputListWidget->currentIndex().isValid() )
|
||||
name = ui->inputListWidget->currentIndex().data().toString();
|
||||
|
||||
QAudioDeviceInfo dev = findInputAudioDeviceInfoByName ( name );
|
||||
|
||||
name = QQtAudioManager::defaultOutputDevice().deviceName();
|
||||
|
||||
if ( ui->outputListWidget->currentIndex().isValid() )
|
||||
name = ui->outputListWidget->currentIndex().data().toString();
|
||||
|
||||
QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name );
|
||||
|
||||
/*使用默认输入、输出设备*/
|
||||
//如果开启这段代码,页面上的输入、输出设备选择,就仅仅是个显示了,不具备操作能力。
|
||||
/*
|
||||
dev = QQtAudioManager::defaultInputDevice();
|
||||
devOut = QQtAudioManager::defaultOutputDevice();
|
||||
*/
|
||||
|
||||
//把设备设进manager去
|
||||
manager.inputDeviceInfo() = dev;
|
||||
manager.outputDeviceInfo() = devOut;
|
||||
|
||||
//这里保证输入、输出使用格式相等 或者 不同
|
||||
//如果格式不同,在mac电脑上本地输入输出设备是可以使用的,但是对于连接的语音蓝牙话筒,却是不可以使用的,原因未知。
|
||||
//格式相同的时候,实在是太好用啦。
|
||||
//这个建议默认就相同,但是,在QQtAudioManager当中,并没有直接将其相等处理,如果用户在readyRead槽函数里,可以更改采样率进行某些特殊处理。一般不需要差异处理的,相等就行了。
|
||||
// int inBit = ui->inBit->currentIndex().data().toInt();
|
||||
// int inChn = ui->inChn->currentIndex().data().toInt();
|
||||
// int inRate = ui->intRate->currentIndex().data().toInt();
|
||||
// QAudioFormat inFmt;
|
||||
// inFmt.setChannelCount ( inChn );
|
||||
// inFmt.setSampleSize ( inBit );
|
||||
// inFmt.setSampleRate ( inRate );
|
||||
// inFmt.setCodec ( "audio/pcm" );
|
||||
// manager.inputAudioFormat() = inFmt;
|
||||
|
||||
QAudioFormat outFmt = manager.outputDeviceInfo().preferredFormat();
|
||||
|
||||
int outBit = outFmt.sampleSize(), outChn = outFmt.channelCount(), outRate = outFmt.sampleRate();
|
||||
|
||||
if ( ui->outBit->currentIndex().isValid() )
|
||||
outBit = ui->outBit->currentIndex().data().toInt();
|
||||
|
||||
if ( ui->outChn->currentIndex().isValid() )
|
||||
outChn = ui->outChn->currentIndex().data().toInt();
|
||||
|
||||
if ( ui->outRate->currentIndex().isValid() )
|
||||
outRate = ui->outRate->currentIndex().data().toInt();
|
||||
|
||||
outFmt.setChannelCount ( outChn );
|
||||
outFmt.setSampleSize ( outBit );
|
||||
outFmt.setSampleRate ( outRate );
|
||||
outFmt.setCodec ( "audio/pcm" );
|
||||
|
||||
manager.inputAudioFormat() = outFmt;
|
||||
manager.outputAudioFormat() = outFmt;
|
||||
|
||||
pline() << "in prefer" << dev.preferredFormat().channelCount() << dev.preferredFormat().sampleRate() <<
|
||||
dev.preferredFormat().sampleSize();
|
||||
|
||||
pline() << "out prefer" << devOut.preferredFormat().channelCount() << devOut.preferredFormat().sampleRate() <<
|
||||
devOut.preferredFormat().sampleSize();
|
||||
|
||||
pline() << "in" << manager.inputAudioFormat().channelCount() << manager.inputAudioFormat().sampleRate() <<
|
||||
manager.inputAudioFormat().sampleSize();
|
||||
|
||||
pline() << "out" << manager.outputAudioFormat().channelCount() << manager.outputAudioFormat().sampleRate() <<
|
||||
manager.outputAudioFormat().sampleSize();
|
||||
|
||||
manager.startInput();
|
||||
manager.startOutput();
|
||||
}
|
||||
|
||||
void MainWindow::readyRead()
|
||||
{
|
||||
//这里是用户实现,任何用户希望做的事情,都在这里做完。
|
||||
//可以 录音、保存文件
|
||||
//可以 直接播放
|
||||
//可以 混音 +保存 +播放...
|
||||
//可以 消音
|
||||
//可以 将pcm转换为其他格式音频
|
||||
//可以 降噪
|
||||
//可以 ...
|
||||
//ptime();//11-12ms 是个10ms timer
|
||||
QByteArray bytes = manager.readAll();
|
||||
manager.write ( bytes );
|
||||
}
|
||||
|
||||
void MainWindow::wavRecReadyRead()
|
||||
{
|
||||
QByteArray bytes = wavRecManager.readAll();
|
||||
//pline() << "recording:" << bytes.size();
|
||||
wavFileManager.write ( bytes );
|
||||
}
|
||||
|
||||
void MainWindow::wavFileReadyRead()
|
||||
{
|
||||
QByteArray bytes = wavFileManager.readAll();
|
||||
//pline() << "playing:" << bytes.size();
|
||||
wavRecManager.write ( bytes );
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_3_clicked()
|
||||
{
|
||||
manager.stopInput();
|
||||
manager.stopOutput();
|
||||
}
|
||||
|
||||
/*bug:Qt 设置音量会报错退出*/
|
||||
void MainWindow::on_inHS_valueChanged ( int value )
|
||||
{
|
||||
return;
|
||||
|
||||
if ( !manager.inputDevice() )
|
||||
return;
|
||||
|
||||
qreal linearVolume;
|
||||
// qreal linearVolume = QAudio::convertVolume ( value / qreal ( 100.0 ),
|
||||
// QAudio::LogarithmicVolumeScale,
|
||||
// QAudio::LinearVolumeScale );
|
||||
|
||||
// pline() << "输入音量" << value << linearVolume << qRound ( linearVolume * 100 ) ;
|
||||
manager.inputManager()->setVolume ( qRound ( linearVolume * 100 ) );
|
||||
}
|
||||
|
||||
/*bug:Qt 设置音量会报错退出*/
|
||||
void MainWindow::on_outHS_valueChanged ( int value )
|
||||
{
|
||||
return;
|
||||
|
||||
if ( !manager.outputDevice() )
|
||||
return;
|
||||
|
||||
qreal vol = qreal ( value ) / 100;
|
||||
pline() << "输出音量" << vol ;
|
||||
manager.outputManager()->setVolume ( vol );
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_4_clicked()
|
||||
{
|
||||
manager.inputAudioFormat() = QQtAudioManager::defaultOutputDevice().preferredFormat();
|
||||
manager.outputAudioFormat() = QQtAudioManager::defaultOutputDevice().preferredFormat();
|
||||
|
||||
pline() << "in prefer" << QQtAudioManager::defaultInputDevice().preferredFormat().channelCount() <<
|
||||
QQtAudioManager::defaultInputDevice().preferredFormat().sampleRate() <<
|
||||
QQtAudioManager::defaultInputDevice().preferredFormat().sampleSize();
|
||||
|
||||
pline() << "out prefer" << QQtAudioManager::defaultOutputDevice().preferredFormat().channelCount() <<
|
||||
QQtAudioManager::defaultOutputDevice().preferredFormat().sampleRate() <<
|
||||
QQtAudioManager::defaultOutputDevice().preferredFormat().sampleSize();
|
||||
|
||||
pline() << "in" << manager.inputAudioFormat().channelCount() << manager.inputAudioFormat().sampleRate() <<
|
||||
manager.inputAudioFormat().sampleSize();
|
||||
|
||||
pline() << "out" << manager.outputAudioFormat().channelCount() << manager.outputAudioFormat().sampleRate() <<
|
||||
manager.outputAudioFormat().sampleSize();
|
||||
|
||||
manager.startDefaultInput();
|
||||
manager.startDefaultOutput();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_5_clicked()
|
||||
{
|
||||
QString name = QQtAudioManager::defaultOutputDevice().deviceName();
|
||||
|
||||
if ( ui->outputListWidget->currentIndex().isValid() )
|
||||
name = ui->outputListWidget->currentIndex().data().toString();
|
||||
|
||||
QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name );
|
||||
|
||||
QQtWavSoundEffect::Instance()->useCustomOutputDevice ( devOut );
|
||||
QQtWavSound()->setLoops ( 3 );
|
||||
QQtWavSound ( conf_res ( "9733.wav" ) );
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_6_clicked()
|
||||
{
|
||||
QString name = QQtAudioManager::defaultOutputDevice().deviceName();
|
||||
|
||||
if ( ui->outputListWidget->currentIndex().isValid() )
|
||||
name = ui->outputListWidget->currentIndex().data().toString();
|
||||
|
||||
QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name );
|
||||
|
||||
QQtWavSoundEffect::Instance()->useCustomOutputDevice ( devOut );
|
||||
QQtWavSound ( conf_res ( "9763.wav" ) );
|
||||
//QSound::play ( conf_res("9763.wav"));
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_7_clicked()
|
||||
{
|
||||
QString name = QQtAudioManager::defaultOutputDevice().deviceName();
|
||||
|
||||
if ( ui->outputListWidget->currentIndex().isValid() )
|
||||
name = ui->outputListWidget->currentIndex().data().toString();
|
||||
|
||||
QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name );
|
||||
|
||||
QQtWavSoundEffect::Instance()->useCustomOutputDevice ( devOut );
|
||||
QQtWavSound()->setLoops ( 1 );
|
||||
QQtWavSound ( conf_res ( "9612.wav" ) );
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define TMPFILE "/sdcard/temp.wav"
|
||||
#else
|
||||
#define TMPFILE "./temp.wav"
|
||||
#endif
|
||||
|
||||
void MainWindow::on_pushButton_8_clicked()
|
||||
{
|
||||
//不需要停止录音?需要
|
||||
//android 不支持./temp.wav....
|
||||
|
||||
//record
|
||||
QAudioDeviceInfo input = QQtAudioManager::defaultInputDevice();
|
||||
wavRecManager.inputDeviceInfo() = input;
|
||||
wavRecManager.inputAudioFormat() = input.preferredFormat();
|
||||
|
||||
//save wav file
|
||||
wavFileManager.outputAudioFormat() = wavRecManager.inputAudioFormat();
|
||||
wavFileManager.setOutputSourceFile ( TMPFILE );
|
||||
|
||||
pline() << "record:" << wavRecManager.inputDeviceInfo().deviceName() << wavRecManager.inputAudioFormat();
|
||||
pline() << "save:" << wavFileManager.outputSourceFile() << wavFileManager.outputAudioFormat();
|
||||
|
||||
//内部存在自动关停。对wav写自动关停,会导致文件被重写。这个函数是录音重新开始,所以可以自动关停。
|
||||
wavFileManager.startOutput();
|
||||
wavRecManager.startInput();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_9_clicked()
|
||||
{
|
||||
//不需要停止放音?需要
|
||||
|
||||
//read wav file
|
||||
wavFileManager.setInputSourceFile ( TMPFILE );
|
||||
|
||||
//play record
|
||||
wavRecManager.outputAudioFormat() = wavFileManager.inputAudioFormat();
|
||||
wavRecManager.outputDeviceInfo() = QQtAudioManager::defaultOutputDevice();
|
||||
|
||||
pline() << "file:" << wavFileManager.inputSourceFile() << wavFileManager.inputAudioFormat();
|
||||
pline() << "play:" << wavRecManager.outputDeviceInfo().deviceName() << wavRecManager.outputAudioFormat();
|
||||
|
||||
//内部存在自动关停。
|
||||
wavRecManager.startOutput();
|
||||
wavFileManager.startInput();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_10_clicked()
|
||||
{
|
||||
wavRecManager.stopInput();
|
||||
wavFileManager.stopOutput();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_11_clicked()
|
||||
{
|
||||
wavFileManager.stopInput();
|
||||
wavRecManager.stopOutput();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_12_clicked()
|
||||
{
|
||||
//android support 16bit but 24bit
|
||||
QQtWavSoundEffect* e0 = QQtWavSound();
|
||||
e0->setTimerInterval ( 100 );
|
||||
QQtWavSound ( conf_res ( "9767.wav" ) );
|
||||
}
|
67
test/voicetest2/mainwindow.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <qqtaudiomanager.h>
|
||||
#include <qqtwavaudiomanager.h>
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow ( QWidget* parent = 0 );
|
||||
~MainWindow();
|
||||
|
||||
QAudioDeviceInfo findInputAudioDeviceInfoByName ( QString devName );
|
||||
|
||||
QAudioDeviceInfo findOutputAudioDeviceInfoByName ( QString devName );
|
||||
|
||||
private slots:
|
||||
void on_pushButton_2_clicked();
|
||||
void currentInputRowChanged ( QModelIndex, QModelIndex );
|
||||
void currentOutputRowChanged ( QModelIndex, QModelIndex );
|
||||
void on_pushButton_clicked();
|
||||
void readyRead();
|
||||
|
||||
//录音到wav
|
||||
void wavRecReadyRead();
|
||||
//读取rec wav播放
|
||||
void wavFileReadyRead();
|
||||
void on_pushButton_3_clicked();
|
||||
|
||||
void on_inHS_valueChanged ( int value );
|
||||
|
||||
void on_outHS_valueChanged ( int value );
|
||||
|
||||
void on_pushButton_4_clicked();
|
||||
|
||||
void on_pushButton_5_clicked();
|
||||
|
||||
void on_pushButton_6_clicked();
|
||||
|
||||
void on_pushButton_7_clicked();
|
||||
|
||||
void on_pushButton_8_clicked();
|
||||
|
||||
void on_pushButton_9_clicked();
|
||||
|
||||
void on_pushButton_10_clicked();
|
||||
|
||||
void on_pushButton_11_clicked();
|
||||
|
||||
void on_pushButton_12_clicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
QQtAudioManager manager;
|
||||
|
||||
QQtAudioManager wavRecManager;
|
||||
QQtWavAudioManager wavFileManager;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
273
test/voicetest2/mainwindow.ui
Normal file
@ -0,0 +1,273 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>751</width>
|
||||
<height>367</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Tab 1</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="1">
|
||||
<widget class="QListWidget" name="inBit"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QListWidget" name="inChn"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QListWidget" name="intRate"/>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QListWidget" name="inputListWidget"/>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>input format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>input device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="0">
|
||||
<widget class="QListWidget" name="outChn"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QListWidget" name="outBit"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QListWidget" name="outRate"/>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QListWidget" name="outputListWidget"/>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>output format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>output device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>start take voice and play</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_4">
|
||||
<property name="text">
|
||||
<string>start take voice
|
||||
and play (default device)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_3">
|
||||
<property name="text">
|
||||
<string>stop (optional)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>refresh device list</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Tab 2</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_5">
|
||||
<property name="text">
|
||||
<string>sound effect 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_6">
|
||||
<property name="text">
|
||||
<string>sound effect 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_7">
|
||||
<property name="text">
|
||||
<string>sound effect 3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_12">
|
||||
<property name="text">
|
||||
<string>sound effect 4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_8">
|
||||
<property name="text">
|
||||
<string>record 0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_10">
|
||||
<property name="text">
|
||||
<string>stop record</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_9">
|
||||
<property name="text">
|
||||
<string>play record 0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_11">
|
||||
<property name="text">
|
||||
<string>stop playing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>input volume</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="inHS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>output volume</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="outHS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>183</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>129</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>Tab 3</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
8
test/voicetest2/voicetest.qrc
Normal file
@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="res/9733.wav">AppRoot/res/9733.wav</file>
|
||||
<file alias="res/9612.wav">AppRoot/res/9612.wav</file>
|
||||
<file alias="res/9763.wav">AppRoot/res/9763.wav</file>
|
||||
<file alias="res/9767.wav">AppRoot/res/9767.wav</file>
|
||||
</qresource>
|
||||
</RCC>
|
70
test/voicetest2/voicetest2.pro
Normal file
@ -0,0 +1,70 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2018-02-08T20:04:18
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = voicetest2
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
CONFIG += mobility
|
||||
MOBILITY =
|
||||
|
||||
#这句话很重要 启动拷贝很多东西
|
||||
system (touch main.cpp)
|
||||
|
||||
include (../../multi-link/multi-link/add_base_manager.pri)
|
||||
|
||||
contains(QSYS_PRIVATE, Android|AndroidX86) {
|
||||
CONFIG += mobility
|
||||
MOBILITY =
|
||||
DISTFILES += \
|
||||
$${PWD}/android/AndroidManifest.xml
|
||||
|
||||
ANDROID_PACKAGE_SOURCE_DIR = $${PWD}/android
|
||||
}
|
||||
|
||||
RESOURCES += \
|
||||
voicetest.qrc
|
||||
|
||||
#这个的设置有特点,要先设置
|
||||
add_version (1,0,0,0)
|
||||
|
||||
#先发布App
|
||||
#app从build到deploy
|
||||
add_deploy()
|
||||
|
||||
#后发布依赖
|
||||
#libQQt从sdk到build和deploy
|
||||
add_dependent_manager(QQt)
|
||||
|
||||
#发布配置文件 把AppRoot里的配置项目拷贝到运行目录和发布目录
|
||||
add_deploy_config($${PWD}/AppRoot)
|
||||
|
||||
message($$ANDROID_EXTRA_LIBS)
|