最近由于着手一个无线电接受机信号处理的工作,需要处理解调模式下传递的PCM数据,绘制波形并播放声音,特此记录。

模拟PCM数据,保存到本地

private void button1_Click(object sender, EventArgs e){string fileName = "123.pcm";FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);//StreamWriter sw = new StreamWriter(fs);//BinaryWriter bw = new BinaryWriter(fs);Random r = new Random();byte[] pcmData = new byte[2048];for (int j = 0; j < 1024; j++){ //for (int i = 0; i < pcmData.Length; i++)r.NextBytes(pcmData);fs.Write(pcmData, 0, pcmData.Length);}fs.Close();}

读取模拟的PCM数据创建WAV文件,并保存到本地

 private void button2_Click(object sender, EventArgs e){InitialStruct();if (readPcm("123.pcm") && InitHeader()){string wavFile = Path.GetRandomFileName() + ".wav";WriteFile(wavFile, databuff);MessageBox.Show(wavFile);//lstMessage.Items.Add("WAVA文件转换成功!" + System.DateTime.Now.ToString());}}/// <summary>/// ERROR MESSAGE/// </summary>const string ERRFILENOTEXITS = "File is Not Exits.";const string ERRFILEISNOTWAVE = "File is not Wava.";/// <summary>/// Wave Hander information/// </summary>struct HeaderType{public byte[] riff;                 /*RIFF类资源文件头部 4byte*/public uint file_len;                /*文件长度4byte*/public byte[] wave;                  /*"WAVE"标志4byte*/public byte[] fmt;                   /*"fmt"标志4byte*/public uint NI1;                     /*过渡字节4byte*/public ushort format_type;           /*格式类别(10H为PCM形式的声音数据)2byte*/public ushort Channels;              /*Channels 1 = 单声道; 2 = 立体声2byte*/public uint frequency;               /*采样频率4byte*/public uint trans_speed;             /*音频数据传送速率4byte*/public ushort dataBlock;             /*数据块的调整数(按字节算的)2byte*/public ushort sample_bits;           /*样本的数据位数(8/16) 2byte*/public byte[] data;                  /*数据标记符"data" 4byte*/public uint wav_len;                 /*语音数据的长度 4byte*/}private HeaderType wavHander;       //定义一个头结构体private byte[] buff = new byte[44]; //header byteprivate byte[] databuff;            //data byte/// <summary>/// 初始化结构体中的数组长度,分配内存/// </summary>private void InitialStruct(){wavHander.riff = new byte[4];//RIFFwavHander.wave = new byte[4];//WAVEwavHander.fmt = new byte[4];//fmt wavHander.data = new byte[4];//data}/// <summary>/// 读取PCM中数据,/// </summary>/// <param name="filepath">文件路径</param>/// <returns>读取成功返回真</returns>private bool readPcm(string filepath){String fileName = filepath;//临时保存文件名if (File.Exists(fileName) == false)//文件不存在{throw new Exception(ERRFILENOTEXITS);}//自读方式打开FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None);if (file == null)//打开成功{file.Close();//关闭文件throw new Exception(ERRFILEISNOTWAVE);}int filelen = (int)file.Length;//获取文件长度databuff = new byte[filelen + 44];//分配 内存file.Read(databuff, 44, filelen);//读取文件,保存在内存中file.Close();//关闭文件return true;}/// <summary>/// 为PCM文件构建文件头,准备转换为WAV文件/// </summary>/// <returns>构建成功返回真</returns>private bool InitHeader(){wavHander.riff = Encoding.ASCII.GetBytes("RIFF");   /*RIFF类资源文件头部 4byte*/wavHander.file_len = (uint)(databuff.Length);              /*文件长度4byte*/wavHander.wave = Encoding.ASCII.GetBytes("WAVE");     /*"WAVE"标志4byte*/wavHander.fmt = Encoding.ASCII.GetBytes("fmt ");      /*"fmt"标志4byte*/wavHander.NI1 = 0x10;                               /*过渡字节4byte*/wavHander.format_type = 0x01;                       /*格式类别(10H为PCM形式的声音数据)2byte*/wavHander.Channels = 0x01;                          /*Channels 1 = 单声道; 2 = 立体声2byte*/wavHander.frequency = 0x1F40;                       /*采样频率4byte*/wavHander.trans_speed = 0x3E80;                     /*音频数据传送速率4byte*/wavHander.dataBlock = 0x02;                         /*数据块的调整数(按字节算的)2byte*/wavHander.sample_bits = 0x10;                       /*样本的数据位数(8/16) 2byte*/wavHander.data = Encoding.ASCII.GetBytes("data");   /*数据标记符"data" 4byte*/wavHander.wav_len = (uint)(databuff.Length - 44);                /*语音数据的长度 4byte*/byte[] byt2;//临时变量 ,保存2位的整数byte[] byt4;//临时变量, 保存4位的整数Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.riff), 0, 4, databuff, 0);/*RIFF类资源文件头部 4byte*/byt4 = BitConverter.GetBytes(wavHander.file_len); /*文件长度4byte*/Array.Copy(byt4, 0, databuff, 4, 4);Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.wave), 0, 4, databuff, 8);/*"WAVE"标志4byte*/Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.fmt), 0, 4, databuff, 12);/*"fmt"标志4byte*/byt4 = BitConverter.GetBytes(wavHander.NI1);/*过渡字节4byte*/Array.Copy(byt4, 0, databuff, 16, 4);byt2 = BitConverter.GetBytes(wavHander.format_type);/*格式类别(10H为PCM形式的声音数据)2byte*/Array.Copy(byt2, 0, databuff, 20, 2);byt2 = BitConverter.GetBytes(wavHander.Channels);/*Channels 1 = 单声道; 2 = 立体声2byte*/Array.Copy(byt2, 0, databuff, 22, 2);byt4 = BitConverter.GetBytes(wavHander.frequency);/*采样频率4byte*/Array.Copy(byt4, 0, databuff, 24, 4);byt4 = BitConverter.GetBytes(wavHander.trans_speed);/*音频数据传送速率4byte*/Array.Copy(byt4, 0, databuff, 28, 4);byt2 = BitConverter.GetBytes(wavHander.dataBlock);/*数据块的调整数(按字节算的)2byte*/Array.Copy(byt2, 0, databuff, 32, 2);byt2 = BitConverter.GetBytes(wavHander.sample_bits);/*样本的数据位数(8/16) 2byte*/Array.Copy(byt2, 0, databuff, 34, 2);Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.data), 0, 4, databuff, 36);/*数据标记符"data" 4byte*/byt4 = BitConverter.GetBytes(wavHander.wav_len); /*语音数据的长度 4byte*/Array.Copy(byt4, 0, databuff, 40, 4);return true;}/// <summary>/// 写文件操作/// </summary>/// <param name="filename">文件路径</param>/// <param name="pbuff">文件数据</param>private void WriteFile(string filename, byte[] pbuff){if (File.Exists(filename) == true)File.Delete(filename);FileStream sw = File.OpenWrite(filename);if (pbuff != null && sw != null){sw.Write(pbuff, 0, pbuff.Length);sw.Close();}}

使用NAudio 播放PCM数据

     WaveOut waveOut;            //播放器BufferedWaveProvider bufferedWaveProvider;       //5s缓存区private void button3_Click(object sender, EventArgs e){waveOut = new WaveOut();WaveFormat wf = new WaveFormat(8000, 16, 1);WaveFormat alawFormat = WaveFormat.CreateALawFormat(8000, 1);// ALawChatCodec alaw = new ALawChatCodec();bufferedWaveProvider = new BufferedWaveProvider(wf);bufferedWaveProvider.DiscardOnBufferOverflow = true;waveOut.Init(bufferedWaveProvider);waveOut.Play();readPcm("123.pcm");bufferedWaveProvider.AddSamples(databuff, 0, databuff.Length);}

代码中的bufferedWaveProvider.DiscardOnBufferOverflow = true;设置必须有,不然会报错:buffer null这个问题困扰了我很长时间

参考文章:c# pcm - jasonlai2016 - 博客园

stream - c# - NAudio buffer full exception - Stack Overflow

PCM详解资料参考:PCM数据格式介绍_SuperLi-CSDN博客_pcm数据格式

PCM音量控制 - 剑痴乎

C# 模拟PCM数据并创建WAV文件相关推荐

  1. S7-200SMART PLC模拟量应用及创建库文件的具体方法

    S7-200SMART PLC模拟量应用及创建库文件的具体方法 具体使用方法可参考以下内容: 模拟量计算公式: OUT = (In_chx - In_RawMin) * (In_EuMax - InE ...

  2. PCM音频数据封装为WAV文件

    ------------------------------------全系列文章目录------------------------------------ PCM(Pulse Code Modul ...

  3. VC++初步实现保存数据为音频WAV文件

    先行基本知识见此 https://blog.csdn.net/bcbobo21cn/article/details/109087252 win7, vc6:新建一个对话框工程:添加一个文本框:为文本框 ...

  4. 什么是PCM?它和.wav文件是什么关系?

    PCM(Pulse Code Modulation----脉码调制录音).所谓PCM录音就是将声音等模拟信号变成符号化的脉冲列,再予以记录.PCM信号是由[1].[0]等符号构成的数字信号,而未经过任 ...

  5. 手工制作Wav文件以及生成播放数据

    上一个帖子写了如何播放wave文件, 除了用已有资源之外, 还可以自己生成wave文件来播放, 因为wave文件很简单, 就是一个文件头, 剩下的都是PCM数据.  这个帖子写写怎么生成wave文件, ...

  6. 【数据预处理】TIMIT语料库WAV文件转换

    1 问题描述 这两天复现代码.先构造数据集,纯净语音.不同噪声.不同SNR的混合语音.其中纯净语音由两部分组成,IEEE corpus和TIMIT. 一开始我用MATLAB中的audioread读取音 ...

  7. 安卓Android开发:使用AudioRecord录音、将录音保存为wav文件、使用AudioTrack保存录音

    一.使用AudioRrecord录音 1.1声明 首先需要声明一个AudioRecord类的实例.之所以需要事先声明,是因为在本例中,录音的启动和结束被封装在两个不同的方法里.而通常来讲," ...

  8. Android音频开发(4):如何存储和解析wav文件

    2019独角兽企业重金招聘Python工程师标准>>> 无论是文字.图像还是声音,都必须以一定的格式来组织和存储起来,这样播放器才知道以怎样的方式去解析这一段数据,例如,对于原始的图 ...

  9. Android音频开发(五)如何存储和解析最简单的音频wav文件

    我们大家都知道,无论是文字.图像还是声音,都必须以一定的格式来组织和存储起来,然后其它的软件再以相同的协议规则,相应的格式才能去打开解析这一段数据,例如,对于原始的图像数据,我们常见的格式有 YUV. ...

最新文章

  1. 程序猿惯用口头禅与内心真实 OS,快来看看你中招没?
  2. SharpDevelop 5.1 调试一个简单会员管理系统
  3. SAP - 银企直联
  4. flutter 一行代码取消 返回按钮
  5. 数学建模论文写作小技巧分享
  6. java 工厂模式的写法_java简单工厂模式是什么
  7. revit API 实现可停靠窗口
  8. apollo-配置管理中心-安装
  9. 64位和32位的寄存器和汇编的比较
  10. 汽车票售票系统 php,客车网上售票系统(2)
  11. 用canvas画布画时钟
  12. Word2003删除空白页的方法汇总
  13. 火箭弹道设计 matlab,航天飞行动力学远程火箭弹道设计大作业 (1)
  14. 逃离迷宫的路径(打印路径)
  15. 160个破解练习之CrackMe 005 CKme002
  16. 可视化大屏设计尺寸_Vue 大屏可视化-屏幕自适应(保持设计尺寸比例)
  17. tidb数据库隔离级别剖析
  18. 小程序 搜索记录功能实现
  19. Acrobat Pro DC 教程:如何使用文本和图片文件创建 PDF?
  20. 移动端Web开发调试之Chrome远程调试(Remote Debugging)

热门文章

  1. Android中高级面试必知必会,绝对干货
  2. 软件行业如何开始创业
  3. linux pv 信号量,pv操作与信号量(示例代码)
  4. MyBatis知识汇总(第四篇)分页:LIMT(SQL方式),RowBounds(Java对象方式)
  5. c语言三种循环结构特点,c语言循环结构(c语言循环结构特点)
  6. 计算机用户不设置密码,笔记本电脑密码设置不了怎么办_笔记本电脑密码不能设置的处理方法-系统城...
  7. 十张图,看数据分析如何赋能销售
  8. 国学大师林语堂献宝:英文学习八要诀
  9. JAVA范例 - Applet小应用程序
  10. UTI 唯一类型标识