当前位置:   article > 正文

C# 模拟PCM数据并创建WAV文件_c# 波形数据转音频数据

c# 波形数据转音频数据

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

模拟PCM数据,保存到本地

  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3. string fileName = "123.pcm";
  4. FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
  5. //StreamWriter sw = new StreamWriter(fs);
  6. //BinaryWriter bw = new BinaryWriter(fs);
  7. Random r = new Random();
  8. byte[] pcmData = new byte[2048];
  9. for (int j = 0; j < 1024; j++)
  10. {
  11. //for (int i = 0; i < pcmData.Length; i++)
  12. r.NextBytes(pcmData);
  13. fs.Write(pcmData, 0, pcmData.Length);
  14. }
  15. fs.Close();
  16. }

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

  1. private void button2_Click(object sender, EventArgs e)
  2. {
  3. InitialStruct();
  4. if (readPcm("123.pcm") && InitHeader())
  5. {
  6. string wavFile = Path.GetRandomFileName() + ".wav";
  7. WriteFile(wavFile, databuff);
  8. MessageBox.Show(wavFile);
  9. //lstMessage.Items.Add("WAVA文件转换成功!" + System.DateTime.Now.ToString());
  10. }
  11. }
  12. /// <summary>
  13. /// ERROR MESSAGE
  14. /// </summary>
  15. const string ERRFILENOTEXITS = "File is Not Exits.";
  16. const string ERRFILEISNOTWAVE = "File is not Wava.";
  17. /// <summary>
  18. /// Wave Hander information
  19. /// </summary>
  20. struct HeaderType
  21. {
  22. public byte[] riff; /*RIFF类资源文件头部 4byte*/
  23. public uint file_len; /*文件长度4byte*/
  24. public byte[] wave; /*"WAVE"标志4byte*/
  25. public byte[] fmt; /*"fmt"标志4byte*/
  26. public uint NI1; /*过渡字节4byte*/
  27. public ushort format_type; /*格式类别(10H为PCM形式的声音数据)2byte*/
  28. public ushort Channels; /*Channels 1 = 单声道; 2 = 立体声2byte*/
  29. public uint frequency; /*采样频率4byte*/
  30. public uint trans_speed; /*音频数据传送速率4byte*/
  31. public ushort dataBlock; /*数据块的调整数(按字节算的)2byte*/
  32. public ushort sample_bits; /*样本的数据位数(8/16) 2byte*/
  33. public byte[] data; /*数据标记符"data" 4byte*/
  34. public uint wav_len; /*语音数据的长度 4byte*/
  35. }
  36. private HeaderType wavHander; //定义一个头结构体
  37. private byte[] buff = new byte[44]; //header byte
  38. private byte[] databuff; //data byte
  39. /// <summary>
  40. /// 初始化结构体中的数组长度,分配内存
  41. /// </summary>
  42. private void InitialStruct()
  43. {
  44. wavHander.riff = new byte[4];//RIFF
  45. wavHander.wave = new byte[4];//WAVE
  46. wavHander.fmt = new byte[4];//fmt
  47. wavHander.data = new byte[4];//data
  48. }
  49. /// <summary>
  50. /// 读取PCM中数据,
  51. /// </summary>
  52. /// <param name="filepath">文件路径</param>
  53. /// <returns>读取成功返回真</returns>
  54. private bool readPcm(string filepath)
  55. {
  56. String fileName = filepath;//临时保存文件名
  57. if (File.Exists(fileName) == false)//文件不存在
  58. {
  59. throw new Exception(ERRFILENOTEXITS);
  60. }
  61. //自读方式打开
  62. FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
  63. if (file == null)//打开成功
  64. {
  65. file.Close();//关闭文件
  66. throw new Exception(ERRFILEISNOTWAVE);
  67. }
  68. int filelen = (int)file.Length;//获取文件长度
  69. databuff = new byte[filelen + 44];//分配 内存
  70. file.Read(databuff, 44, filelen);//读取文件,保存在内存中
  71. file.Close();//关闭文件
  72. return true;
  73. }
  74. /// <summary>
  75. /// 为PCM文件构建文件头,准备转换为WAV文件
  76. /// </summary>
  77. /// <returns>构建成功返回真</returns>
  78. private bool InitHeader()
  79. {
  80. wavHander.riff = Encoding.ASCII.GetBytes("RIFF"); /*RIFF类资源文件头部 4byte*/
  81. wavHander.file_len = (uint)(databuff.Length); /*文件长度4byte*/
  82. wavHander.wave = Encoding.ASCII.GetBytes("WAVE"); /*"WAVE"标志4byte*/
  83. wavHander.fmt = Encoding.ASCII.GetBytes("fmt "); /*"fmt"标志4byte*/
  84. wavHander.NI1 = 0x10; /*过渡字节4byte*/
  85. wavHander.format_type = 0x01; /*格式类别(10H为PCM形式的声音数据)2byte*/
  86. wavHander.Channels = 0x01; /*Channels 1 = 单声道; 2 = 立体声2byte*/
  87. wavHander.frequency = 0x1F40; /*采样频率4byte*/
  88. wavHander.trans_speed = 0x3E80; /*音频数据传送速率4byte*/
  89. wavHander.dataBlock = 0x02; /*数据块的调整数(按字节算的)2byte*/
  90. wavHander.sample_bits = 0x10; /*样本的数据位数(8/16) 2byte*/
  91. wavHander.data = Encoding.ASCII.GetBytes("data"); /*数据标记符"data" 4byte*/
  92. wavHander.wav_len = (uint)(databuff.Length - 44); /*语音数据的长度 4byte*/
  93. byte[] byt2;//临时变量 ,保存2位的整数
  94. byte[] byt4;//临时变量, 保存4位的整数
  95. Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.riff), 0, 4, databuff, 0);/*RIFF类资源文件头部 4byte*/
  96. byt4 = BitConverter.GetBytes(wavHander.file_len); /*文件长度4byte*/
  97. Array.Copy(byt4, 0, databuff, 4, 4);
  98. Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.wave), 0, 4, databuff, 8);/*"WAVE"标志4byte*/
  99. Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.fmt), 0, 4, databuff, 12);/*"fmt"标志4byte*/
  100. byt4 = BitConverter.GetBytes(wavHander.NI1);/*过渡字节4byte*/
  101. Array.Copy(byt4, 0, databuff, 16, 4);
  102. byt2 = BitConverter.GetBytes(wavHander.format_type);/*格式类别(10H为PCM形式的声音数据)2byte*/
  103. Array.Copy(byt2, 0, databuff, 20, 2);
  104. byt2 = BitConverter.GetBytes(wavHander.Channels);/*Channels 1 = 单声道; 2 = 立体声2byte*/
  105. Array.Copy(byt2, 0, databuff, 22, 2);
  106. byt4 = BitConverter.GetBytes(wavHander.frequency);/*采样频率4byte*/
  107. Array.Copy(byt4, 0, databuff, 24, 4);
  108. byt4 = BitConverter.GetBytes(wavHander.trans_speed);/*音频数据传送速率4byte*/
  109. Array.Copy(byt4, 0, databuff, 28, 4);
  110. byt2 = BitConverter.GetBytes(wavHander.dataBlock);/*数据块的调整数(按字节算的)2byte*/
  111. Array.Copy(byt2, 0, databuff, 32, 2);
  112. byt2 = BitConverter.GetBytes(wavHander.sample_bits);/*样本的数据位数(8/16) 2byte*/
  113. Array.Copy(byt2, 0, databuff, 34, 2);
  114. Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(wavHander.data), 0, 4, databuff, 36);/*数据标记符"data" 4byte*/
  115. byt4 = BitConverter.GetBytes(wavHander.wav_len); /*语音数据的长度 4byte*/
  116. Array.Copy(byt4, 0, databuff, 40, 4);
  117. return true;
  118. }
  119. /// <summary>
  120. /// 写文件操作
  121. /// </summary>
  122. /// <param name="filename">文件路径</param>
  123. /// <param name="pbuff">文件数据</param>
  124. private void WriteFile(string filename, byte[] pbuff)
  125. {
  126. if (File.Exists(filename) == true)
  127. File.Delete(filename);
  128. FileStream sw = File.OpenWrite(filename);
  129. if (pbuff != null && sw != null)
  130. {
  131. sw.Write(pbuff, 0, pbuff.Length);
  132. sw.Close();
  133. }
  134. }

使用NAudio 播放PCM数据 

  1. WaveOut waveOut; //播放器
  2. BufferedWaveProvider bufferedWaveProvider; //5s缓存区
  3. private void button3_Click(object sender, EventArgs e)
  4. {
  5. waveOut = new WaveOut();
  6. WaveFormat wf = new WaveFormat(8000, 16, 1);
  7. WaveFormat alawFormat = WaveFormat.CreateALawFormat(8000, 1);
  8. // ALawChatCodec alaw = new ALawChatCodec();
  9. bufferedWaveProvider = new BufferedWaveProvider(wf);
  10. bufferedWaveProvider.DiscardOnBufferOverflow = true;
  11. waveOut.Init(bufferedWaveProvider);
  12. waveOut.Play();
  13. readPcm("123.pcm");
  14. bufferedWaveProvider.AddSamples(databuff, 0, databuff.Length);
  15. }

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

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

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

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

PCM音量控制 - 剑痴乎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/106475
推荐阅读
相关标签
  

闽ICP备14008679号