一、通过Nuget安装NAudio包
开发工具:vs2019
点击Visual Studio 2019的工具->NuGet包管理器-》管理解决方案的NuGet的程序包-》浏览-》在搜索框中输入NAudio-》点击安装
二、获取short类型或者byte类型的音频数据
我的数据是一组short类型的正弦波信号,存储在txt中,如下图所示:
通过C#读取文档并存储在short数组中
string filePath = "20500Left.txt"; // txt文件路径
short[] audioData = new short[48000 * 2]; //双声道数据
int index = 0;
// 读取txt文档并按逗号分割文本
using (StreamReader reader = new StreamReader(filePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(',');
foreach (string part in parts)
{
//Console.WriteLine(part);
audioData[index] = Convert.ToInt16(part);
index++;
}
}
}
将short变为byte类型的数据(如果本身你的音频数据就是byte类型就不需要执行下边操作)
// 将short[]音频数据转换为byte[]数据
byte[] byteData = new byte[audioData.Length * 2]; // short类型占2个字节
Buffer.BlockCopy(audioData, 0, byteData, 0, byteData.Length);
三、循环播放自己的音频数据,重写WaveStream类
主要是重写了Read这个函数,读到数据流末尾,就从开头读取。
class LoopingWaveStream : WaveStream
{
private WaveStream sourceStream;
public LoopingWaveStream(WaveStream sourceStream)
{
this.sourceStream = sourceStream;
}
public override WaveFormat WaveFormat => sourceStream.WaveFormat;
public override long Length => sourceStream.Length;
public override long Position
{
get => sourceStream.Position;
set => sourceStream.Position = value;
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = 0;
while (bytesRead < count)
{
int read = sourceStream.Read(buffer, offset + bytesRead, count - bytesRead);
if (read == 0)
{
// 如果读取到末尾,重新从头开始读取
sourceStream.Position = 0;
}
bytesRead += read;
}
return bytesRead;
}
}
将上边的byte类型的数据转换为Stream类型,并填入WaveOut对象中,进行播放
// 创建内存流
using (MemoryStream stream = new MemoryStream(byteData))
{
// 从内存流中创建RawSourceWaveStream //采样率设置为48000,位深设置位16位,通道为双声道
RawSourceWaveStream rawStream = new RawSourceWaveStream(stream, new WaveFormat(48000, 16, 2));
LoopingWaveStream loopingWaveStream=new LoopingWaveStream(rawStream);
// 使用WaveOutEvent播放音频数据
WaveOut waveOut = new WaveOut();
waveOut.Init(loopingWaveStream);//想要循环播放
//waveOut.Init(rawStream); //不想要循环播放
waveOut.Play();
//下边两种方式的循环播放会有爆音,不采用。
//waveOut.PlaybackStopped += (sender, e) =>
// {
// if (waveOut.PlaybackState == PlaybackState.Stopped)
// {
// rawStream.Position = 0;
// waveOut.Play();
// }
// };
//while (waveOut.PlaybackState == PlaybackState.Playing)
//{
// if (rawStream.Position >= rawStream.Length)
// {
// rawStream.Position = 0;
// //Console.WriteLine("Audio stream reached the end.");
// //break;
// }
//}
Console.WriteLine("Press Enter to stop playback.");
Console.ReadLine(); //阻塞线程
waveOut.Stop(); //停止播放
waveOut.Dispose();
}
四、完整代码:
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Media;
using System.Text;
using System.Threading.Tasks;
namespace 播放short
{
class LoopingWaveStream : WaveStream
{
private WaveStream sourceStream;
public LoopingWaveStream(WaveStream sourceStream)
{
this.sourceStream = sourceStream;
}
public override WaveFormat WaveFormat => sourceStream.WaveFormat;
public override long Length => sourceStream.Length;
public override long Position
{
get => sourceStream.Position;
set => sourceStream.Position = value;
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = 0;
while (bytesRead < count)
{
int read = sourceStream.Read(buffer, offset + bytesRead, count - bytesRead);
if (read == 0)
{
// 如果读取到末尾,重新从头开始读取
sourceStream.Position = 0;
}
bytesRead += read;
}
return bytesRead;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("开始");
string filePath = "20500Left.txt"; // txt文件路径
short[] audioData = new short[48000 * 2]; //双声道数据
int index = 0;
// 读取txt文档并按逗号分割文本
using (StreamReader reader = new StreamReader(filePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(',');
foreach (string part in parts)
{
//Console.WriteLine(part);
audioData[index] = Convert.ToInt16(part);
index++;
}
}
}
// 将short[]音频数据转换为byte[]数据
byte[] byteData = new byte[audioData.Length * 2]; // short类型占2个字节
Buffer.BlockCopy(audioData, 0, byteData, 0, byteData.Length);
//方式1///
// 创建内存流
using (MemoryStream stream = new MemoryStream(byteData))
{
// 从内存流中创建RawSourceWaveStream //采样率设置为48000,位深设置位16位,通道为双声道
RawSourceWaveStream rawStream = new RawSourceWaveStream(stream, new WaveFormat(48000, 16, 2));
LoopingWaveStream loopingWaveStream=new LoopingWaveStream(rawStream);
// 使用WaveOutEvent播放音频数据
WaveOut waveOut = new WaveOut();
waveOut.Init(loopingWaveStream);//想要循环播放
//waveOut.Init(rawStream); //不想要循环播放
waveOut.Play();
//下边两种方式的循环播放会有爆音,不采用。
//waveOut.PlaybackStopped += (sender, e) =>
// {
// if (waveOut.PlaybackState == PlaybackState.Stopped)
// {
// rawStream.Position = 0;
// waveOut.Play();
// }
// };
//while (waveOut.PlaybackState == PlaybackState.Playing)
//{
// if (rawStream.Position >= rawStream.Length)
// {
// rawStream.Position = 0;
// //Console.WriteLine("Audio stream reached the end.");
// //break;
// }
//}
Console.WriteLine("Press Enter to stop playback.");
Console.ReadLine(); //阻塞线程
waveOut.Stop(); //停止播放
waveOut.Dispose();
}
}
}
}
结束
记录学习过程。