C# 模拟PCM数据并创建WAV文件

最近由于着手一个无线电接受机信号处理的工作,需要处理解调模式下传递的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 byte
        private byte[] databuff;            //data byte
       
          
            
       
        /// <summary>
        /// 初始化结构体中的数组长度,分配内存
        /// </summary>
        private void InitialStruct()
        {
            wavHander.riff = new byte[4];//RIFF
            wavHander.wave = new byte[4];//WAVE
            wavHander.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音量控制 - 剑痴乎

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

破浪征程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值