精华内容
下载资源
问答
  • 使用QT实现pcm和wav文件相互转换,读取wav音频格式等。其中有些数据类型属于qt特有如qint32, QString等完全可以转成int,std::string,移植的话转成相应类型即可。
  • 读取文件时用Qfile file.read先读取表头信息再读取音频数据 表头信息读取参考了https://blog.csdn.net/GoForwardToStep/article/details/52789253 数据滤波处理时使用计算出滤波参数后,在线性卷积时发现总会...

    在读取文件时用Qfile file.read先读取表头信息再读取音频数据

    表头信息读取参考了https://blog.csdn.net/GoForwardToStep/article/details/52789253

    数据滤波处理时使用计算出滤波参数后,在线性卷积时发现总会卡死到双重for循环中(下面是已经修改后的)

            for( int i=0; i<nSampleCnt; i++)
            {
                for( int j=0; j<nFilterLen; ++j )
                {
                    res[i+j] += (short)(pFilterData[j]*(double)wavData[i]);
                }
            }

    后来发现读取文件时使用的是QByteArray,给类型读取时每一位是char型,而数据处理时是short型,所以需要进行一下转换

    读取时的转换:

    short* wavData;    
    QByteArray gbry;
    gbry=fileInfo.readAll();
    char low;
    char high;
    for(int i=0;i<WavFileHeader.nDataLength;i+=2){
            high=gbry.at(i+1);
            low=gbry.at(i);
            wavData[i/2]=(high<<4)|low;
    }

    写入时的转换

    QByteArray byArr;
                char low;
                char high;
                for(int i=0;i<WavFileHeader.nDataLength;i+=2){
                      low=wavData[i/2]%16;
                      high=wavData[i/2]/16;
                      byArr[i]=low;
                      byArr[i+1]=high;
                }
    file.write(byArr);

    在转换时要注意high与low的顺序

    疑问:使用以上方式将刚读取的wavData直接再重新写入后文件会有很大的噪声,是因为什么?感觉数据传输中没有丢失吧,

    希望有大佬可以告知一下原因!

    展开全文
  • QtWAV文件解析

    千次阅读 2017-10-15 19:28:03
    最近看了一下Qt的处理音频方面的资料,本身利用QAudioInput 和 QAudioOutput 就可以实现录音和播放功能,代码也很简单,但是录音生成的文件并不能用播放器打开,就算更改后缀名也无法识别(有时候下载的一些音频...

    简介

    最近看了一下Qt的处理音频方面的资料,本身利用QAudioInput 和 QAudioOutput 就可以实现录音播放功能,代码也很简单,但是录音生成的文件并不能用播放器打开,就算更改后缀名也无法识别(有时候下载的一些音频文件通过修改文件名可以播放)。本质上通过QAudioInput生成的音频文件并没有什么格式,只是一堆音频数据,换言之就是没有文件头,只有数据,当然播放器识别不出来了。这里我们把QAudioInput生成的音频文件转换为wav音频格式就可以用播放器播放了。下面就详细介绍一下WAV文件 , 下一篇中将用代码来实现录音/播放and录音文件(raw/pcm)转wav格式功能 。

    WAV文件分析

    WAV文件简介

    WAV为微软公司开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT A LAW等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几! WAV打开工具是WINDOWS的媒体播放器。

    通常使用三个参数来表示声音,声道数、采样频率和采样位数。采样位数分为8位,16位,24位三种,声道有单声道和立体声之分,单声道振幅数据为n*1矩阵点,立体声为n*2矩阵点,取样频率一般有11025Hz(11kHz) ,22050Hz(22kHz)和44100Hz(44kHz) 三种,不过尽管音质出色,但在压缩后的文件体积过大!相对其他音频格式而言是一个缺点,其文件大小的计算方式为:WAV格式文件所占容量(B) = (取样频率 X量化位数X 声道) X 时间 / 8 (字节= 8bit) 每一分钟WAV格式的音频文件的大小为10MB,其大小不随音量大小及清晰度的变化而变化。

    WAV是最接近无损的音乐格式,所以文件大小相对也比较大。WAVE是录音时用的标准的WINDOWS文件格式,文件的扩展名为“WAV”,数据本身的格式为PCM或压缩型,属于无损音乐[1] 格式的一种。 
    符合 RIFF(Resource Interchange File Format)规范。所有的WAV都有一个文件头,这个文件头音频流的编码参数。数据块的记录方式是little-endian字节顺序,标志符并不是字符串而是单独的符号。

    ————摘自百度百科

    WAV文件特点

    WAV音频格式的优点包括:简单的编/解码(几乎直接存储来自模/数转换器(ADC)的信号)、普遍的认同/支持以及无损耗存储。WAV格式的主要缺点是需要音频存储空间。对于小的存储限制或小带宽应用而言,这可能是一个重要的问题。WAV格式的另外一个潜在缺陷是在32位WAV文件中的2G限制,这种限制已在为SoundForge开发的W64格式中得到了改善。

    常见的WAV文件使用PCM无压缩编码,这使WAV文件的质量极高,体积也出奇大,对于PCM WAV,恐怕也只有无损压缩的音频才能和其有相同的质量,平时我们见的什么mp3,wma(不含wmalossless)和wav的质量都是差很远的!这点可以通过频谱看出,即使320kbps的mp3和wav一比,也要自卑了!

    ————摘自百度百科

    WAV文件头分析

    下图为wav文件的基本格式。

    这里写图片描述这里写图片描述

    仔细看上图,其实wav文件是由若干个数据块组成的。wav文件头信息包括从上图的RIFF头到数据块中的块头这一部分为wav文件的文件头(简而言之就是去除数据块中的块数据即为文件头,也就是不包含音频数据)

    // wav文件头信息结构
    struct WAVFILEHEADER
    {
        // RIFF 头;
        char RiffName[4];
        unsigned long nRiffLength;
    
        // 数据类型标识符;
        char WavName[4];
    
        // 格式块中的块头;
        char FmtName[4];
        unsigned long nFmtLength;
    
        // 格式块中的块数据;
        unsigned short nAudioFormat;
        unsigned short nChannleNumber;
        unsigned long nSampleRate;
        unsigned long nBytesPerSecond;
        unsigned short nBytesPerSample;
        unsigned short nBitsPerSample;
    
        // 扩展信息(附加信息),根据 nFmtLength 来判断;
        // 扩展域大小;
        unsigned short nAppendMessage;
        // 扩展域信息数据;
        char* AppendMessageData;
    
        //Fact块,可选字段,一般当wav文件由某些软件转化而成,则包含该块和扩展信息;
        char FactName[4];
        unsigned long nFactLength;
        char FactData[4];
    
        // 数据块中的块头;
        char    DATANAME[4];
        unsigned long   nDataLength;
    };
    
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    这里我们定义一个结构体分别对应上图中wav文件头从上到下不同的块。


    不同块数据的介绍

    RIFF 头

    • RIFFNAME —— (“RIFF”) 
      资源交换文件标志,以RIFF标示

    • nRIFFLength —— ( 文件长度-8 ) 
      整个wav文件大小减去RIFFNAME和nRIFFLength所占用的字节数

    数据类型标识符

    • WavName —— (“WAVE”) 
      波形文件标识符,wav文件标志,表示是wav文件

    格式块中的块头

    • FmtName —— (”fmt “)注意这里fmt后面还要加一个空格以满足4个字节
    • 波形格式标志

    • nFmtLength —— (一般为16 或者 18 也有 大于18的数值) 
      表示格式块中块数据大小,通常为16,为18时表示格式块中块数据有附加信息(即扩展域大小-nAppendMessage),主要由一些软件制成的wav格式中含有该2个字节,当大于18时,nFmtLength - 18 (或者用nAppendMessage代替) 即为扩展域信息数据所占的字节数(上图中也指出),具体包含什么数据也只有生成该wav文件的生成者知道了。

    格式块中的块数据

    • nAudioFormat ——(0001H) 
      格式种类,也可以说是编码方式(值为1时,表示数据为线性PCM编码,大于1时表示有压缩的编码)

    • nChannleNumber ——(1 或者 2) 
      音频通道数目,1–单通道(声道);2–双通道(声道)

    • nSampleRate 
      采样频率(每秒样本数)

    • nBytesPerSecond —— (采样频率 × 音频通道数 × 每次采样得到的样本位数 / 8) 
      波形数据传输速率(每秒平均字节数)

    • nBytesPerSample —— (通道数×每次采样得到的样本数据位值/8) 
      数据块对齐单位(每个采样需要的字节数)

    • nBitsPerSample 
      每次采样得到的样本数据位数值(Qt助手中提到一般设置为8 或 16 , 有一些系统可能支持更高的数据位数,百度百科中提到可取值 8、16、24)

    • nAppendMessage 
      扩展域大小,扩展信息(可选),根据nFmtLength 的值判断是否存在

    • AppendMessageData 
      扩展域信息数据,扩展信息(可选),根据nFmtLength 的值判断是否存在

    Fact块(可选)

    • FactName (“fact”) 
      Fact块名,表面这是一个Fact块,此块目前由是否nFmtLength决定是否存在,与扩展信息一致。

    • nFactLength 
      Fact块数据长度 , 一般取值为4

    • FactData 
      Fact块数据 , 具体包含什么信息只有生成该wav文件的生成者知道了

    数据块中的块头

    • DATANAME —— (“data”) 
      数据块标识符

    • nDataLength 
      采样数据总字节数 / 数据块中块数据总大小(即wav文件实际音频数据所占的大小)

    注意

    需要注意的一点,上面叙述中添加了一个Fact块(可选块),也就是格式块中的扩展域后面可能存在的一块,目前认为是存在扩展域就会存在Fact块。见下图,在格式块中根据nFmtLength(格式块中块数据大小) 的值,一般情况下为16字节,即不包含Fact块,看图中fmt子块中WAVEFORMATEX占了18个字节,通常情况下为16字节,包含附加信息Fact块就是18字节(也会大于18字节)。 
    从下图中可以看出wav文件都是以 52 49 46 46 开头(将wav文件用编辑器打开),也可以根据这几个值初步判断是否是一个wav文件。

    通过以上对wav格式的分析,我们可以对一个wav文件进行解析,获取文件具体的信息,下篇中将会给出具体代码实现来解析一个wav文件,输出文件的信息。

    这里写图片描述


    wav文件属性的计算

    如果我们知道采样频率、每次采样得到的样本数据位数、声道数及wav文件大小就可以推出wav文件的时间,其实我们右击显示wav文件属性的时候,会有时间、比特率,但是这里显示的时间都是整数,不是很精确,比如一个小于1s的文件,查看属性显示时间长度就为0,所以想要得到精确的时间就得通过计算得出。 
    Qt 之 解析wav文件的头信息(详细分析、对比不同wav文件的数据) 中我们给出了如何解析wav文件头信息的方法,这样我们就可以计算出wav文件的音频时长。

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

    比特率(kbs) = 波形数据传输速率 × 8 / 1000

    WAV文件所占大小(字节) = 波形数据传输速率 × 音频文件时长

    音频文件时长(秒) = WAV文件所占容量 / 波形数据传输速率

    Qt 之 WAV文件属性计算(比特率、文件大小、文件时长)文章中给出了具体分析。


    关于数据库中数据bit位置安排方式

    数据块中的块数据才是真正的声音数据。除非安装其它特殊软件,否则Windows目前仅提供WAVE_FORMAT_PCM (pcm)一种数据格式,即脉冲编码调制(Pulse Code Modulation).根据声道数不同及取样位数的不同,安排4bit位的位置,wav数据的bit位置可以分成以下几种形式,见下图。

    这里写图片描述


    参考资料:

    http://blog.csdn.net/zhihu008/article/details/7854533

    http://www.2cto.com/os/201312/267541.html

    http://www.cnblogs.com/tiandsp/archive/2012/10/17/2728585.html


    以上是经过多番资料查询以及个人的一些看法总结整理出,基本上概括了wav文件头信息中各个数据表示的实际意义以及取值,如果文章中出现错误,还请指出,谢谢

    展开全文
  • Qt 播放Wav音频文件

    2016-04-26 10:25:16
    Qt使用QSoundEffect来播放wav文件 附官方说明:This class allows you to play uncompressed audio files (typically WAV files) in a generally lower latency way, and is suitable for "feedback" type sounds in...
  • Qt5 Wav波形文件录音及分析

    热门讨论 2014-07-31 16:57:55
    Qt做的Wav录音程序,可以得到声音的波形图,分析声音的响度和频率。Qt5用得不习惯,发布起来比较困难,所以就不发布执行档了。如果是Linux的话,编译肯定没问题的。建议用Qt5.2.1以上的版本编译。
  • Qt播放WAV格式音频文件的两种方法

    万次阅读 多人点赞 2016-04-23 09:03:14
    这两种方法都需要在.pro文件中加入multimedia模块。 方法一、使用QAudioOutput #include #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QFile inputFile; ...

            这两种方法都需要在.pro文件中加入multimedia模块。

    方法一、使用QAudioOutput

    #include <QApplication>
    #include <QFile>
    #include <QAudioFormat>
    #include <QAudioOutput>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QFile inputFile;
        inputFile.setFileName("test.wav");
        inputFile.open(QIODevice::ReadOnly);
    
        //设置采样格式
        QAudioFormat audioFormat;
        //设置采样率
        audioFormat.setSampleRate(44100);
        //设置通道数
        audioFormat.setChannelCount(2);
        //设置采样大小,一般为8位或16位
        audioFormat.setSampleSize(16);
        //设置编码方式
        audioFormat.setCodec("audio/pcm");
        //设置字节序
        audioFormat.setByteOrder(QAudioFormat::LittleEndian);
        //设置样本数据类型
        audioFormat.setSampleType(QAudioFormat::UnSignedInt);
    
        QAudioOutput *audio = new QAudioOutput( audioFormat, 0);
        audio->start(&inputFile);
        return a.exec();
    }

            注意这里采样率、通道数和采样大小的设置,本例只能用来播放无损的WAV。网上很多代码将采样率设置成8000、通道数设置为1、采样大小设置为8,这样虽然也能播放WAV,但是没有任何其他说明,也没提供播放所用的WAV文件,导致很多童鞋在网上找个WAV,播放时出现“嗡嗡”声,根本听不清。

            “什么是无损”参考:http://blog.csdn.net/caoshangpa/article/details/51218597

            “如何下载和制作无损WAV”参考:http://blog.csdn.net/caoshangpa/article/details/51218994

    方法二、使用QSoundEffect

    #include <QApplication>
    #include <QSoundEffect>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QSoundEffect effect;
        effect.setSource(QUrl::fromLocalFile("test.wav"));
        //循环播放
        effect.setLoopCount(QSoundEffect::Infinite);
        //设置音量,0-1
        effect.setVolume(0.8f);
        effect.play();
        return a.exec();
    }

    原创不易,转载请标明出处:https://blog.csdn.net/caoshangpa/article/details/51224587

    展开全文
  • 简述在 QtWAV文件解析 中我们对wav文件的文件头中的数据进行了分析,在 Qt之实现录音播放及raw(pcm)转wav格式 中我们实现了录音/播放功能,并将.raw格式的音频文件转为wav格式文件,那我们拿到一个wav文件如何...

    简述

    Qt 之 WAV文件解析 中我们对wav文件的文件头中的数据进行了分析,在 Qt之实现录音播放及raw(pcm)转wav格式 中我们实现了录音/播放功能,并将.raw格式的音频文件转为wav格式文件,那我们拿到一个wav文件如何获取文件的具体信息呢,这一篇将叙述对wav文件的头信息进行解析。

    注意

    在看这篇文章前希望读者看一下 Qt 之 WAV文件解析Qt之实现录音播放及raw(pcm)转wav格式 这两篇文章, 本篇文章也是基于这两篇的基础上进行叙述,如果读者对wav文件的格式有了一定的了解,也可以直接阅读。

    代码之路

    Qt 之 WAV文件解析 中我们对wav文件头进行了详细的介绍,如果不清楚的可以了解一下。wav的文件头其实就是一个数据结构,结构中保存了一系列参数,那我们从wav文件中一一解析出这些参数。

    // wav文件头信息结构
    struct WAVFILEHEADER
    {
        // RIFF 头;
        char RiffName[4];
        unsigned long nRiffLength;
    
        // 数据类型标识符;
        char WavName[4];
    
        // 格式块中的块头;
        char FmtName[4];
        unsigned long nFmtLength;
    
        // 格式块中的块数据;
        unsigned short nAudioFormat;
        unsigned short nChannleNumber;
        unsigned long nSampleRate;
        unsigned long nBytesPerSecond;
        unsigned short nBytesPerSample;
        unsigned short nBitsPerSample;
    
        // 附加信息(可选),根据 nFmtLength 来判断;
        // 扩展域大小;
        unsigned short nAppendMessage;
        // 扩展域信息;
        char* AppendMessageData;
    
        //Fact块,可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk;
        char FactName[4];
        unsigned long nFactLength;
        char FactData[4];
    
        // 数据块中的块头;
        char    DATANAME[4];
        unsigned long   nDataLength;
    
        // 以下是附加的一些计算信息;
        int fileDataSize;               // 文件音频数据大小;
        int fileHeaderSize;             // 文件头大小;
        int fileTotalSize;              // 文件总大小;
    
    
        // 理论上应该将所有数据初始化,这里只初始化可选的数据;
        WAVFILEHEADER()
        {
            nAppendMessage = 0;
            AppendMessageData = NULL;
            strcpy(FactName, "");
            nFactLength = 0;
            strcpy(FactData, "");
        }
    
    };
    
    // 解析wav文件的头信息;
    bool anlysisWavFileHeader(QString fileName)
    {
        QFile fileInfo(fileName);
        if (!fileInfo.open(QIODevice::ReadOnly))
        {
            return false;
        }
    
        WAVFILEHEADER WavFileHeader;
        // 读取 资源交换文件标志 "RIFF";
        fileInfo.read(WavFileHeader.RiffName, sizeof(WavFileHeader.RiffName));
    
    
        // 读取 RIFF 头后字节数;
        fileInfo.read((char*)&WavFileHeader.nRiffLength, sizeof(WavFileHeader.nRiffLength));
        // 读取 波形文件标识符 "WAVE";
        fileInfo.read(WavFileHeader.WavName, sizeof(WavFileHeader.WavName));
    
        // 读取 波形格式标志 "fmt ";
        fileInfo.read(WavFileHeader.FmtName, sizeof(WavFileHeader.FmtName));
    
        // 读取 格式块中块数据大小;
        fileInfo.read((char*)&WavFileHeader.nFmtLength, sizeof(WavFileHeader.nFmtLength));
    
        // 读取 格式种类;
        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.nBytesPerSample, sizeof(WavFileHeader.nBytesPerSample));
    
        // 读取 每次采样得到的样本数据位数值;
        fileInfo.read((char*)&WavFileHeader.nBitsPerSample, sizeof(WavFileHeader.nBitsPerSample));
    
        // 根据格式块中块数据大小,判断是否有附加信息;
        QString strAppendMessageData;           // 保存扩展域中的扩展信息;
        if (WavFileHeader.nFmtLength >= 18)
        {
            // 读取附加信息占两个字节;
            fileInfo.read((char*)&WavFileHeader.nAppendMessage, sizeof(WavFileHeader.nAppendMessage));
            // 这里 特别注意 nFmtLength 一般情况下是 16 或者18 ,但是有一个wav文件 nFmtLength 为50;
            // 说明我们读取完fmt格式块后面有附加信息,上面一行代码读取了两个字节数据
            // 这两个字节即为扩展域的大小,而剩余的 50 - 18 = 32字节即为扩展域中的扩展信息;
            // 对于扩展域中保存了什么格式的数据暂时无法得知,先用char型数组保存;
            // 这里 扩展域大小 可以通过 WavFileHeader.nAppendMessage (从文件中读取的扩展域大小) 也可以通过 nFmtLength(格式块长度) - 18 得到;
            int appendMessageLength = WavFileHeader.nFmtLength - 18;
            WavFileHeader.AppendMessageData = new char[appendMessageLength];
            fileInfo.read(WavFileHeader.AppendMessageData, appendMessageLength);
            // 这里也可以在末尾加字符结束符查看数据,但是现在不确定扩展信息的具体格式;
            //WavFileHeader.AppendMessageData[appendMessageLength] = '\0';
            // 转成QString 查看扩展信息数据;
            strAppendMessageData = QString(WavFileHeader.AppendMessageData);
        }
    
        // 由于Fact块为可选,可能存在,所以需要判断;
        char chunkName[5];
        fileInfo.read(chunkName, sizeof(chunkName) - 1);
        // 需要加上字符结束符 '\0',否则转成QString会出错,通过strlen来计算chunkName的字符长度也会出错。
        chunkName[4] = '\0';
        QString strChunkName(chunkName);
        if (strChunkName.compare("fact") == 0)
        {
            // 存在fact块,读取数据;
            strcpy(WavFileHeader.FactName, chunkName);
            // 读取fact块长度;
            fileInfo.read((char*)&WavFileHeader.nFactLength, sizeof(WavFileHeader.nFactLength));
            // 读取fact块数据;
            fileInfo.read(WavFileHeader.FactData, sizeof(WavFileHeader.FactData));
    
            // 存在Fact块 , 读取 数据块标识符;
            fileInfo.read(WavFileHeader.DATANAME, sizeof(WavFileHeader.DATANAME));
        }
        else
        {
            // 不存在Fact块,直接赋值;
            strcpy(WavFileHeader.DATANAME, chunkName);
        }
    
    
        // 读取 数据块大小;
        fileInfo.read((char*)&WavFileHeader.nDataLength, sizeof(WavFileHeader.nDataLength));
    
        // 读取 音频数据大小;
        WavFileHeader.fileDataSize = fileInfo.readAll().size();
    
        // 文件总大小;
        WavFileHeader.fileTotalSize = WavFileHeader.nRiffLength + 8;
    
        //文件头大小;
        WavFileHeader.fileHeaderSize = WavFileHeader.fileTotalSize - WavFileHeader.fileDataSize;
    
        fileInfo.close();
        return true;
    }

    程序截图

    文件一:

    这里写图片描述 这里写图片描述


    文件二:

    这里写图片描述 这里写图片描述

    从上述图片看来,文件一和文件二都带有扩展信息(附加信息) , 可以根据 nFmtLength 是否为18 ,而上两个文件中nFmtLength 的值为18 确实有扩展信息 ,,而扩展信息包含了两个数据字段,一个是扩展域大小(占两个字节),另一个是扩展域信息数据(大小不定),从图上可以看出nFmtLength的值为18,而Fmt块的大小为16,所以多出的2个字节即为扩展域大小,从图中可以看出nAppendMessage值为0,表示没有扩展信息(也可以通过nFmtLength - 18来计算,不过前提是 nFmtLength >= 18 , 具体可以看上述代码),也就无需读取扩展信息 , 可以看出图中AppendMessageData的值为NULL

    同时文件一和文件二的nFmtLength都为18,包含了扩展信息中的扩展域大小,同时特别注意两个文件都包含了Fact块

    文件三:

    这里写图片描述 这里写图片描述

    文件四:

    这里写图片描述 这里写图片描述

    从文件三和文件四看来,nFmtLength的值为16 , 表示没有扩展信息(附加信息) ,这两个wav音频文件没有包含扩展信息,也没有Fact块

    文件五:

    这里写图片描述 这里写图片描述

    从文件五中可以看到 nFmtLength 的值为50 , 刚开始看到这个值感觉这个文件可能已经损坏或者有问题,因为之前查阅一些资料发现 一般nFmtLength 的值为 16或者18 (为18 时会包含扩展信息),但此时数值为 50 ,这里我不禁疑惑,后来我想想 扩展信息中包含 扩展域大小和扩展域信息数据,那么扩展域大小占两个字节,那么 50 - 16 - 2 = 32 字节,多出来的32 字节即为扩展域信息数据,而用代码解析出来的数据也有问题,后来分析是因为我没有将这32字节数据读取出来,而是将这32个字节的数据赋值给了扩展信息后面的数据,导致扩展信息后面的Fact块 和Data块解析有问题,所以再次修改代码加上判断是否存在扩展域信息数据

    现在看文件五右边这张图中我们发现 nAppendMessage 的值为 32 ,也验证了多出来的 32字节的扩展域信息数据 , 由于不知道扩展信息的数据结构,暂时先用char型数组接收数据, AppendMessageData现在有了数据,但是显示乱码,这里我们就无需去分析扩展信息中的数据了,由于扩展信息是因为一些软件自己生成的,所以我们只要将扩展信息读取出来即可,也避免后面的数据读取出错。

    综合分析

    同时注意文件五不仅包含了扩展信息,也包含了扩展域信息数据,同时也存在Fact数据块,所以综合这几个文件数据对比,我们可以初步猜测包含了扩展信息就会存在Fact数据块,但是也不能完全断定,还需继续研究,最好是通过代码解析得出具体数据。扩展信息主要由一些软件制成的wav格式中包含,具体有何意义有待研究。

    头信息数据中nRiffLength这个值代表 RIFF 块后字节数也就是 整个文件大小 - 8 ,经过对比这个值也是正确的。从文件分析的结果中我们可以看到各个音频文件的各项参数。通过不同文件的对比,主要的三个参数:声道数、采样频率和采样位数 (nChannleNumber、nSampleRate和nBitsPerSample),都不一致,这几个值也决定了音频文件的音质,文件大小等属性。

    同时我们观察 nDataLengthfileDataSize 这两个参数 : nDataLength是wav文件头中记录wav文件中实际音频数据所占的大小 , 而 fileDataSize 从代码中可以看出是在读取完文件头,后面数据的大小,而文件头后的数据也就是实际的音频数据,看文件一、文件二和文件五 中 nDataLengthfileDataSize这两个值并不相等,目前猜测可能是由于扩展信息的原因,从文件三和文件四中我们看到这两个值是相等的,而且文件三和文件四并不包含扩展信息,但是也不能完全断定,还需继续研究,进一步得到确切的论证。


    我在刚开始解析wav文件时都是按照wav文件的标准格式(即不包含扩展信息 和 Fact块)去解析头信息,而测试的wav文件都是用 上一篇文章中 通过QAudioInput 类生成 .raw文件再转成 .wav文件,而自己生成的.wav文件的文件头都是自己添加的,而且不包含扩展信息 和 Fact块,所以用代码解析过程中并没有遇到问题,后来用了网上下载的一些.wav文件,发现解析出了问题。

    回到上图中,文件三和文件四为标准的wav格式,所以解析没有问题,而文件一和文件二 包含了扩展信息 和 Fact块 , 导致解析出现了问题, 这里我通过判断了nFmtLength 的长度是否为18得出是否包含扩展信息,而此时我只是读了两个字节的 扩展域大小 , 对于文件一和文件二 中不包含 扩展域信息数据是没有问题的,下面我又判断下面的字段是否是”fact”得出是否包含Fact块,好了文件一和文件二解析数据也都正确,这下我以为已经成功了。

    接着,我又试了文件五,发现nFmtLength这个字段值为 50 , 除去扩展域大小(2个字节)发现多出了32( = 50 - 16 - 2 )字节,而nAppendMessage 的值也是32,经过分析 这多出的 32 字节数据即为 扩展域信息数据 。后面在通过 nFmtLength >= 18 来得出是否包含扩展域大小,再通过nFmtLength - 18 > 0 来得出是否包含扩展域信息数据(其实这里也可以通过nAppendMessage的值来判断,具体代码中也给出了详细的注释)。

    以上是我写这篇文章时所尽经历的整个过程,本以为解析过程很简单,但是真正去做时却遇到了各种问题,这也是缺乏对wav文件格式的认知。整篇文章的内容以及代码也是经过了反复修改,通过对wav文件头的解析也让我对wav文件有了进一步的认识,同时也发现了之前的文章 Qt 之 WAV文件解析 一文中的一些错误,我也做了进一步的修改。

    文章文字叙述较多,详细地讲解了解析过程中遇到的问题以及解决办法。整篇文章也是花了很长时间来完成,希望读者能够认真仔细看完(不过看之前最好看一下 Qt 之 WAV文件解析 这篇文章),也希望能够多多支持。我相信看完后对wav文件就应该有了一定的认识,对后面如何处理wav文件就好办多了。后面会继续讲述Qt音频处理相关的知识。同时在写这篇博客时发现了给char 数组赋值时遇到的一些问题 ,后面也将会单独对这些问题进行论述,敬请期待。

    Good Night !


    wav音频文件下载

    展开全文
  • Qt显示WAV音频文件的波形图/频谱图

    千次阅读 2020-12-04 15:58:48
    https://download.csdn.net/download/yulinxx/13507147 wav文件读取类 WaveFile #ifndef WAVEFILE_H #define WAVEFILE_H #include #include #include using namespace std; class WaveFile { public: struct ...
  • Qt显示wav波形图

    2020-12-13 00:39:22
    2.涉及QT内容: 2.1 使用QMediaPlayer来播放音频。 2.2 使用QPixmap绘制波形图。 3.波形图绘制原理。 注意:本文章只实现声道数为1,2,采样位数为8,16的wav非压缩(PCM)音频; ①根据绘制区域得到宽高,再得出...
  • 整个程序实现了一个录音机功能,QAudioInput生成的raw文件不能直接用播放器播放,这里将生成的.raw文件转成wav格式的音频文件。这样既可用QAudioOutput来播放,又可以用播放器来播放,详情见 ...
  • Qt 的 QAudioOutput 类播放 WAV 音频文件最近有一个项目,需要同时控制 4 个声卡播放不同的声音,声音文件很简单就是没有任何压缩的 wav 文件。 如果只是播放 wav 文件,那么 Qt 里简单的 QSound 类是最适合的。...
  • wav格式音频文件播放并显示波形

    热门讨论 2012-10-11 21:40:44
    wav格式音频文件播放,并显示波形同时可以选择播放
  • 封装了一个播放WAV文件的类,可以播放指定的WAV文件、并且可以指定放声音的扬声器设备,在有多个声卡的系统上非常实用。 三、核心代码 3.1 widget.cpp文件代码 #include "widget.h" #include "ui_widget.h" #...
  • Qt5绘制wav波形图

    万次阅读 2013-05-30 22:20:38
    任务:用qt5画wav波形图 步骤: 1、新建项目 - Qt Gui 应用 - 工程名 - 基类选择QWidget(类名默认为widget) - 完成,生成widget.h, main.cpp, widget.cpp 2、接下来要添加一个自定义类,用来读入wav头文件信息...
  • Qt之TCP传输文件

    2020-02-20 16:12:24
    Qt之TCP传输文件概述:代码示例:.proclient.hclient.cppserver.hserver.cpp测试结果over:文末一句话: 概述: 功能: TCP(Transmission Control Protocol传输控制协议)是一种面向连接的、可靠的、基于字节流的...
  • WAV文件的二进制格式解析

    千次阅读 2020-02-25 21:52:13
    文章目录第一个子chunk另一个子chunk实例:用C语言解析wav文件运行结果:![image-20200110113424163.png](https://img-blog.csdnimg.cn/20200225215022578.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5...
  • 本示例工程主要介绍了如何使用QAudioInput设置采集的参数,指定采集的设备等,采集数据到内存,并保存为wav文件。请看博客https://www.jianshu.com/p/04302b8f2e7e
  • QT文件合成

    2020-01-17 20:36:25
    widget.cpp文件 #include "widget.h" #include "ui_widget.h" #include "QDebug" #include <QFileInfoList> #include <qdir> #include<QFileDialog> Widget::Widget(QWidget *paren...
  • Qt 中的文件操作

    千次阅读 2018-08-07 19:38:27
    2、Qt中的文件操作(QFile、QFileInfo、QTemporaryFile) 1、QFile、QFileInfo 2、QTemporaryFile 3、文本流和数据流(QTextStream和QDataStream) 1、文件类型 2、文本流和数据流 4、缓冲区操作与目录操作...
  • wav文件波形

    2011-10-20 10:04:31
    C++实现的画wav音频文件波形,凑够20字。。。。。。
  • Qt 播放音频文件

    万次阅读 多人点赞 2016-04-26 10:52:55
    Qt播放音频文件的方法有好多中,简单介绍几种 不过一下几种方式都需要在Qt工程文件中添加 QT += multimedia 第一 QMediaPlayer类 可以播放MP3文件,同时使用也是最简单的了,具体代码 { player = new ...
  • QT发送数据之udp发送文件 为了处理丢包等原因,发送端每发送一帧接收端都要回复,最后要判断文件接收是否完整。 发送文件 1.浏览选择文件 filepath.clear();//初始化文件路径 fdialog = new QFileDialog();//这里...
  • Qt识别文件类型的正确姿势

    千次阅读 2019-08-05 23:47:14
    一般我们识别文件类型都是从文件的后缀区分,这样做可以识别出文件格式。但在Qt里有更好的实现方法。
  • QT实现音频实时传输

    2019-01-09 10:24:24
    该代码支持音频 的实时传输,采用UDP协议方式,当收到音频数据时自动发送到接收端
  • wav 文件是有文件头的,播放时我们需要跳过文件头,否则开始播放有一小段时间的噪音,具体做法是:1、读取文件 2、读取位置指到文件头之后即可。 在资源交换文件RIFF标准中,所有的数据被组织成“块(chunk)”格式...
  • 读取播放wav文件并显示波形

    千次阅读 2012-02-12 15:36:25
    原文:http://www.codeguru.com/cpp/g-m/multimedia/audio/article.php/c4739
  • 1、用 QFile 打开 WAV 文件,读出文件头信息,看看是否符合音频播放设备的要求 QAudioDeviceInfo m_audioOutputDevice;//可以获取音频输出设备的信息,比如哪个音频设备、判断是否支持某个文件 m_...
  • wav文件拼接详细步骤

    千次阅读 2017-09-14 09:39:04
    * 解析头部,并获得文件指针指向数据开始位置的InputStreram,记得使用后需要关闭 */ private static Header resolveHeader (File wavFile) throws IOException { FileInputStream fis = new ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,442
精华内容 576
关键字:

qt读取wav文件