使用C#播放short[]或者byte[]音频

本文介绍了如何通过NuGet在VisualStudio2019中安装NAudio包,然后处理short和byte类型的音频数据,包括读取txt文件、数据转换,以及自定义LoopingWaveStream类实现音频循环播放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、通过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();
            }


        }
    }
}

结束

记录学习过程。

<think>好的,我现在需要解决用户的问题:如何在C#中将数据流转换为音频播放。用户提到了之前引用过处理short[]或byte[]数组的方法,以及生成WAV文件的内容。首先,我得回忆一下C#中处理音频播放的相关知识。 用户的需求是将纯数据(比如short数组或byte数组)转换为音频并实时播放。根据之前的引用,用户可能已经通过读取文件得到了这些数据,现在需要播放它们。我需要考虑使用哪些库或API来实现这一点。 首先,System.Media命名空间中的SoundPlayer类可以播放WAV文件,但它不支持流式播放,只能播放完整的文件。如果用户需要实时播放或处理流数据,这可能不够。因此可能需要更底层的API,比如Windows上的WinMM API,或者使用NAudio这样的第三方库。 NAudio是一个常用的音频处理库,支持多种音频格式和流式播放使用NAudio的WaveOut类或WasapiOut类可以更灵活地处理音频流。用户的数据如果是PCM格式,可以直接通过NAudio的BufferedWaveProvider来缓冲数据并播放。 另外,用户提到需要将数据流转换为音频,可能需要先确定数据的格式,比如采样率、位深度、声道数等。例如,引用中的代码提到了双声道数据,采样率可能是48kHz,每个样本是16位(short类型)。这些信息在初始化音频播放设备时需要用到。 接下来,我需要整理实现步骤。首先,将数据转换为正确的格式,比如byte数组。如果数据已经是short数组,需要将其转换为byte数组,因为音频API通常接受byte数组。然后,配置音频输出设备的参数,如WaveFormat。接着,使用BufferedWaveProvider来持续添加音频数据,并启动播放。 还需要考虑如何处理实时数据流,比如从网络或传感器不断接收的数据,需要持续写入缓冲区,确保播放的连续性。可能需要多线程处理,防止主线程阻塞。 另外,用户可能需要将数据保存为WAV文件,这在之前的引用中也提到过。如果需要,可以使用NAudio的WaveFileWriter来创建WAV文件,但这可能不是当前问题的重点,但可以作为扩展功能。 最后,要检查代码示例是否正确,确保转换和播放过程没有错误。比如,使用Buffer.BlockCopy正确转换short数组到byte数组,设置正确的WaveFormat,处理可能的异常情况,如缓冲区溢出或下溢。 总结步骤:1. 引用NAudio库;2. 配置音频格式;3. 转换数据到byte数组;4. 使用BufferedWaveProvider缓冲数据;5. 使用WaveOut播放;6. 处理实时数据流。同时,提供示例代码和注意事项,如格式匹配、缓冲区管理和多线程处理。</think>在C#中将数据流转换为音频播放的实现步骤如下: ### 一、核心实现方法 1. **定义音频格式参数** ```csharp var waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2); //44.1kHz采样率,双声道 ``` 2. **使用NAudio库创建播放设备** ```csharp using NAudio.Wave; var waveOut = new WaveOutEvent(); var bufferedProvider = new BufferedWaveProvider(waveFormat); waveOut.Init(bufferedProvider); waveOut.Play(); ``` 3. **数据转换与播放** ```csharp short[] pcmData = GetAudioData(); //从数据流获取short数组 byte[] byteData = new byte[pcmData.Length * 2]; Buffer.BlockCopy(pcmData, 0, byteData, 0, byteData.Length); bufferedProvider.AddSamples(byteData, 0, byteData.Length); ``` ### 二、完整示例代码 ```csharp using NAudio.Wave; using System; public class AudioStreamPlayer { private BufferedWaveProvider bufferedProvider; private WaveOutEvent waveOut; public void InitAudio(int sampleRate = 44100, int channels = 2) { var format = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); bufferedProvider = new BufferedWaveProvider(format); waveOut = new WaveOutEvent(); waveOut.Init(bufferedProvider); waveOut.Play(); } public void FeedAudio(byte[] pcmData) { bufferedProvider.AddSamples(pcmData, 0, pcmData.Length); } // 转换short数组到byte[] public static byte[] ShortToByte(short[] data) { byte[] byteArray = new byte[data.Length * 2]; Buffer.BlockCopy(data, 0, byteArray, 0, byteArray.Length); return byteArray; } } ``` ### 三、关键注意事项 1. **格式匹配**:必须保证`WaveFormat`参数与原始数据完全一致(采样率、位深度、声道数) 2. **缓冲区管理**:建议保持200ms以上的缓冲数据量防止卡顿,可通过`bufferedProvider.BufferedDuration`监测 3. **多线程处理**:音频数据填充建议使用独立线程,避免界面卡死 ### 四、扩展应用 若需要生成WAV文件,可使用NAudio的`WaveFileWriter`: ```csharp WaveFileWriter.CreateWaveFile("output.wav", new RawSourceWaveStream( new MemoryStream(byteData), waveFormat)); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值