音频压缩代码集锦···-程序员宅基地

技术标签: matlab  

// conv.cpp
//
// convert a PCM wave to some other format
//转换一个PCM格式的wav到其他格式

#include <windows.h>    //包含头文件 windows.h
#include <mmsystem.h>//包含头文件mmsystem.h
#include <mmreg.h>    // Multimedia registration多媒体注册
#include <msacm.h> // Audio Compression Manager音频压缩管理器
#include <stdio.h>
#include <math.h>


// Locate a driver that supports a given format and return its ID
//寻找一个支持给定格式的驱动并返回其ID
typedef struct
{
 HACMDRIVERID hadid;//指向HACMDRIVERID的句柄
 WORD wFormatTag;//32位无符号整型 格式标签
} FIND_DRIVER_INFO;//结构FIND_DRIVER_INFO包含2个元素:HACMDRIVERID hadid 和WORD wFormatTag

 

// callback function for format enumeration
//用来枚举格式的回调函数
BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)//LPACMFORMATDETAILS pafd指向ACM格式详情的指针
{
 FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;//FIND_DRIVER_INFO类型的指针 指向驱动信息
 if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) {//如果详情中的格式标签==驱动信息指针pdi中的格式标签
  // found it如果能找到
  pdi->hadid = hadid;
  return FALSE; // stop enumerating停止枚举
 }
 return TRUE; // continue enumerating继续枚举
}

 

// callback function for driver enumeration
//用来枚举驱动的回调函数
BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
{
 FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
 
 // open the driver打开驱动
 HACMDRIVER had = NULL;//HACMDRIVER类型的变量 had 指向ACM驱动的句柄
 MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
 if (mmr) {
  // some error错误
  return FALSE; // stop enumerating停止枚举
 }
 // enumerate the formats it supports枚举它支持的格式
 DWORD dwSize = 0;
 mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
 if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
 WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
 memset(pwf, 0, dwSize);
 pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
 pwf->wFormatTag = pdi->wFormatTag;
 ACMFORMATDETAILS fd;
 memset(&fd, 0, sizeof(fd));
 fd.cbStruct = sizeof(fd);
 fd.pwfx = pwf;
 fd.cbwfx = dwSize;
 fd.dwFormatTag = pdi->wFormatTag;
 mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)pdi, 0); 
 free(pwf);
 acmDriverClose(had, 0);
 if (pdi->hadid || mmr) {
  // found it or some error找到了 或 有错误
  return FALSE; // stop enumerating停止枚举
 }
 return TRUE; // continue enumeration继续枚举
}

// locate the first driver that supports a given format tag
//寻找支持给定格式标签的第一个驱动
HACMDRIVERID find_driver(WORD wFormatTag)
{
 FIND_DRIVER_INFO fdi;
 fdi.hadid = NULL;
 fdi.wFormatTag = wFormatTag;
 MMRESULT mmr = acmDriverEnum(find_driver_enum, (DWORD)(VOID*)&fdi, 0);
 if (mmr) return NULL;
 return fdi.hadid;
}

// get a description of the first format supported for a given tag
//获取驱动的描述 这个驱动是第一个支持给定标签的驱动。
WAVEFORMATEX* get_driver_format(HACMDRIVERID hadid, WORD wFormatTag)
{
 // open the driver打开驱动
 HACMDRIVER had = NULL;
 MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
 if (mmr)
 {
  return NULL;
 }
 
 // allocate a structure for the info
 //为信息分配一个结构
 DWORD dwSize = 0;
 mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
 if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
 WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
 memset(pwf, 0, dwSize);
 pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
 pwf->wFormatTag = wFormatTag;
 
 ACMFORMATDETAILS fd;
 memset(&fd, 0, sizeof(fd));
 fd.cbStruct = sizeof(fd);
 fd.pwfx = pwf;
 fd.cbwfx = dwSize;
 fd.dwFormatTag = wFormatTag;
 
 // set up a struct to control the enumeration
 //建立一个结构用于控制枚举
 FIND_DRIVER_INFO fdi;
 fdi.hadid = NULL;
 fdi.wFormatTag = wFormatTag;
 
 mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)&fdi, 0); 
 acmDriverClose(had, 0);
 if ((fdi.hadid == NULL) || mmr)
 {
  free(pwf);
  return NULL;
 }
 
 return pwf;
}

 

int main(int argc, char* argv[])
{
 // First we create a wave that might have been just recorded.
 //首先我们建立一个也许是刚刚录制完毕的wave
 // The format is 11.025 kHz, 8 bit mono PCM which is a recording
 //它的格式是11.025 kHz,8位 单声道PCM
 // format available on all machines.
 //它是一种在所有机器上都有效的录音格式
 // our sample wave will be 1 second long and will be a sine wave
 //我们的wave样本是长度为一秒的正弦波,频率是1kHz,刚好1000个周期
 // of 1kHz which is exactly 1,000 cycles
 
 WAVEFORMATEX wfSrc;
 memset(&wfSrc, 0, sizeof(wfSrc));
 wfSrc.cbSize = 0;
 wfSrc.wFormatTag = WAVE_FORMAT_PCM; // pcm
 wfSrc.nChannels = 1; // mono单声道
 wfSrc.nSamplesPerSec = 11025; // 11.025 kHz
 wfSrc.wBitsPerSample = 8; // 8 bit
 wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8;
 wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign;
 
 DWORD dwSrcSamples = wfSrc.nSamplesPerSec;
 BYTE* pSrcData = new BYTE [dwSrcSamples]; // 1 second duration
 BYTE* pData = pSrcData;
 double f = 1000.0;
 double pi = 4.0 * atan(1.0);
 double w = 2.0 * pi * f;
 for (DWORD dw = 0; dw < dwSrcSamples; dw++)
 {
  double t = (double) dw / (double) wfSrc.nSamplesPerSec;
  *pData++ = 128 + (BYTE)(127.0 * sin(w * t));
 }
 
 
 // Select a format to convert to选择一个要转换的格式
  //WORD wFormatTag = WAVE_FORMAT_ADPCM;
  //WORD wFormatTag = WAVE_FORMAT_IMA_ADPCM;
  //WORD wFormatTag = WAVE_FORMAT_GSM610;
  //WORD wFormatTag = WAVE_FORMAT_ALAW;
  //WORD wFormatTag = WAVE_FORMAT_MULAW;
  //WORD wFormatTag = 0x32; // MSN
 WORD wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;
 
 // Now we locate a CODEC that supports the destination format tag
 //现在我们选取一个支持目标格式的编码器(CODEC)
 HACMDRIVERID hadid = find_driver(wFormatTag);
 if (hadid == NULL)
 {
  printf("No driver found\n");
  exit(1);
 }
 printf("Driver found (hadid: %4.4lXH)\n", hadid);
 
 // show some information about the driver
 //显示这个驱动的一些信息
 ACMDRIVERDETAILS dd;
 dd.cbStruct = sizeof(dd);
 MMRESULT mmr = acmDriverDetails(hadid, &dd, 0);
 printf("     Short name: %s\n", dd.szShortName);
 printf("     Long name:    %s\n", dd.szLongName);
 printf("     Copyright:    %s\n", dd.szCopyright);
 printf("     Licensing:    %s\n", dd.szLicensing);
 printf("     Features:     %s\n", dd.szFeatures);
 
 // get the details of the format取得格式的详情
 // Note: this is just the first of one or more possible formats for the given tag
 //注意:也许有多个目标格式支持给定的格式,而这只是第一个。
 WAVEFORMATEX* pwfDrv = get_driver_format(hadid, wFormatTag);
 if (pwfDrv == NULL) {
  printf("Error getting format info\n");
  exit(1);
 }
 printf("Driver format: %u bits, %lu samples per second\n", pwfDrv->wBitsPerSample, pwfDrv->nSamplesPerSec);
 
 // get a PCM format tag the driver supports
 //取得一个驱动支持的PCM格式标签
 // Note: we just pick the first supported PCM format which might not really
 //注意:我们只是选取了第一个支持PCM格式的,也许这个不是最好的选择。
 // be the best choice.
 WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM);
 if (pwfPCM == NULL) {
  printf("Error getting PCM format info\n");
  exit(1);
 }
 printf("PCM format: %u bits, %lu samples per second\n", pwfPCM->wBitsPerSample, pwfPCM->nSamplesPerSec);
 
 
 // convert the source wave to the PCM format supported by the CODEC
 //转换源wave到编码器支持的PCM格式
 // we use any driver that can do the PCM to PCM conversion
 //我们使用任何可以完成PCM到PCM转换的驱动
 HACMSTREAM hstr = NULL;
 mmr = acmStreamOpen(&hstr,
        NULL, // any driver任意驱动
        &wfSrc, // source format源格式
        pwfPCM, // destination format目标格式
        NULL, // no filter无过滤
        NULL, // no callback无回调
        0, // instance data (not used)实例数据(未使用)
        ACM_STREAMOPENF_NONREALTIME); // flags
 if (mmr)
 {
  printf("Failed to open a stream to do PCM to PCM conversion\n");
  exit(1);
 }
 
 // allocate a buffer for the result of the conversion.
 //为转换结果分配缓存
 DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8;
 DWORD dwDst1Samples = dwSrcSamples * pwfPCM->nSamplesPerSec / wfSrc.nSamplesPerSec;
 DWORD dwDst1Bytes = dwDst1Samples * pwfPCM->wBitsPerSample / 8;
 BYTE* pDst1Data = new BYTE [dwDst1Bytes];
 
#ifdef _DEBUG
 // fill the dest buffer with zeroes just so we can see if anything got
 //
 // converted in the debugger
 memset(pDst1Data, 0, dwDst1Bytes);
#endif
 
 // fill in the conversion info
 ACMSTREAMHEADER strhdr;
 memset(&strhdr, 0, sizeof(strhdr));
 strhdr.cbStruct = sizeof(strhdr);
 strhdr.pbSrc = pSrcData; // the source data to convert
 strhdr.cbSrcLength = dwSrcBytes;
 strhdr.pbDst = pDst1Data;
 strhdr.cbDstLength = dwDst1Bytes;
 
 // prep the header
 mmr = acmStreamPrepareHeader(hstr, &strhdr, 0);
 
 // convert the data
 printf("Converting to intermediate PCM format...\n");
 mmr = acmStreamConvert(hstr, &strhdr, 0);
 if (mmr)
 {
  printf("Failed to do PCM to PCM conversion\n");
  exit(1);
 }
 printf("Converted OK\n");
 
 // close the stream
 acmStreamClose(hstr, 0);
 
 ///
 // convert the intermediate PCM format to the final format
 
 // open the driver
 HACMDRIVER had = NULL;
 mmr = acmDriverOpen(&had, hadid, 0);
 if (mmr)
 {
  printf("Failed to open driver\n");
  exit(1);
 }
 
 // open the conversion stream
 // Note the use of the ACM_STREAMOPENF_NONREALTIME flag. Without this
 // some software compressors will report error 512 - not possible
 mmr = acmStreamOpen(&hstr,
        had, // driver handle
        pwfPCM, // source format
        pwfDrv, // destination format
        NULL, // no filter
        NULL, // no callback
        0, // instance data (not used)
        ACM_STREAMOPENF_NONREALTIME); // flags
 if (mmr)
 {
  printf("Failed to open a stream to do PCM to driver format conversion\n");
  exit(1);
 }
 
 // allocate a buffer for the result of the conversion.为转换结果分配一个缓冲
 // compute the output buffer size based on the average byte rate基于平均字节率来计算输出缓冲区的大小
 // and add a bit for randomness
 // the IMA_ADPCM driver fails the conversion without this extra space
 DWORD dwDst2Bytes = pwfDrv->nAvgBytesPerSec * dwDst1Samples / pwfPCM->nSamplesPerSec;
 dwDst2Bytes = dwDst2Bytes * 3 / 2; // add a little room增加一点空间
 BYTE* pDst2Data = new BYTE [dwDst2Bytes];
 
#ifdef _DEBUG
 // fill the dest buffer with zeroes just so we can see if anything got
 // converted in the debugger用0填充目标缓冲,由此我们可以在调试中看到转换了的东西
 memset(pDst2Data, 0, dwDst2Bytes);
#endif
 
 // fill in the conversion info填充转换信息
 ACMSTREAMHEADER strhdr2;
 memset(&strhdr2, 0, sizeof(strhdr2));
 strhdr2.cbStruct = sizeof(strhdr2);
 strhdr2.pbSrc = pDst1Data; // the source data to convert
 strhdr2.cbSrcLength = dwDst1Bytes;
 strhdr2.pbDst = pDst2Data;
 strhdr2.cbDstLength = dwDst2Bytes;
 
 // prep the header准备wav头
 mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0);
 
 // convert the data
 printf("Converting to final format...\n");
 mmr = acmStreamConvert(hstr, &strhdr2, 0);
 if (mmr)
 {
  printf("Failed to do PCM to driver format conversion\n");
  exit(1);
 }
 printf("Converted OK\n");
 
 // close the stream and driver关闭流和驱动
 mmr = acmStreamClose(hstr, 0);
 mmr = acmDriverClose(had, 0);
 
 // show the conversion stats显示转换状态
 printf("Source wave had %lu bytes\n", dwSrcBytes);
 printf("Converted wave has %lu bytes\n", strhdr2.cbDstLengthUsed);
 printf("Compression ratio is %f\n", (double) dwSrcBytes / (double) strhdr2.cbDstLengthUsed);
 
 return 0;
}

转载于:https://www.cnblogs.com/xiaopengblog/p/3171884.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33978016/article/details/94520417

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签