PC platform play hard disk OGG, MP3, WAV file in Unity3D

The Unity3D PC platform itself supports the direct use of www to read local ogg, wav, but it cannot read byte[], byte array format, which is a bit for people who are used to bass and fmod inconvenient.

I searched around and found a C# audio library called NAudio, which is open source and free.

https://archive.codeplex.com/?p=naudio

https://github.com/naudio/NAudio

Simply and rudely A binary release, and then nuget the ogg extension

Install-Package NAudio.Vorbis  

For usage, refer to the following 3 addresses

https://blog.csdn.net/qq992817263/article/details/54647741

https://gamedev.stackexchange .com/questions/114885/how-do-i-play-mp3-files-in-unity-standalone

https://stackoverflow.com/questions/24624939/using-vorbis-and-naudio -to-play-ogg-files

In simple terms, create a new NAudioPlayer.cs file with the following content

using UnityEngine;

using System.IO;
using System;
using NAudio;
using NAudio.Wave;

public static class NAudioPlayer
{
static NVorbis.VorbisReader vorbis;
public static AudioClip FromOggData(byte[] data)
{
// Load the data into a stream
MemoryStream oggstream = new MemoryStream(data);

vorbis
= new NVorbis.VorbisReader(oggstream, false );

int samplecount = (int)(vorbis.SampleRate * vorbis.TotalTime.TotalSeconds);

// AudioClip audioClip = AudioClip.Create("clip", samplecount , vorbis.Channels, vorbis.SampleRate, false, true, OnAudioRead, OnAudioSetPosition);
AudioClip audioClip = AudioClip.Create("ogg clip", samplecount, vorbis.Channels, vorbis.SampleRate, false, OnAudioRead);
// Return the clip
return audioClip;
}
static void OnAudioRead(float[] data)
{
var f = new float[data.Length];
vorbis.ReadSamples(f,
0, data.Length);
for (int i = 0; i )
{
data[i] = f[i];
}
}
static void OnAudioSetPosition(int newPosition)
{
vorbis.DecodedTime
= new TimeSpan(newPosition); //Only used to rewind the stream, we won't be seeking
}
public static AudioClip FromWavData(byte[] data)
{
WAV wav
= new WAV(data);
AudioClip audioClip
= AudioClip.Create("wavClip< span style="color: #800000;">"
, wav.SampleCount, 1, wav.Frequency, false);
audioClip.SetData(wav.LeftChannel,
0);
return audioClip;
}
public static AudioClip FromMp3Data(byte[] data)
{
// Load the data into a stream
MemoryStream mp3stream = new MemoryStream(data);
// Convert the data in the stream to WAV format
Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);
WaveStream waveStream
= WaveFormatConversionStream.CreatePcmStream(mp3audio);
// Convert to WAV data
WAV wav = new WAV(AudioMemStream(waveStream).ToArray());
Debug.Log(wav);
AudioClip audioClip
= AudioClip.Create("mp3Clip< span style="color: #800000;">", wav.SampleCount, 1, wav.Frequency, false);
audioClip.SetData(wav.LeftChannel,
0);
// Return the clip
return audioClip;
}

private static MemoryStream AudioMemStream(WaveStream waveStream)
{
MemoryStream outputStream
= new MemoryStream();
using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Position
= 0;
waveStream.Read(bytes,
0, Convert.ToInt32(waveStream. Length));
waveFileWriter.Write(bytes,
0, bytes.Length);
waveFileWriter.Flush();
}
return outputStream;
}
}

/* From http://answers.unity3d.com/questions/737002/wav-byte-to-audioclip.html */
public class WAV
{

// convert two bytes to one float in the range -1 to 1
static float bytesToFloat(byte firstByte, byte secondByte)
{
// convert two bytes to one short (little endian) span>
short s = (short)((secondByte << 8) | firstByte);
// convert to range from -1 to (just below) 1
return s / 32768.0F;
}

static int bytesToInt(byte[] bytes, int offset = 0)
{
int value = 0;
for (int i = 0; i <4; i++)
{
value
|= ((int)bytes[offset + i]) << (i * 8);
}
return value;
}
// properties
public float[] LeftChannel {get; internal set;}
public float[] RightChannel {get; internal set;}
public int ChannelCount {get; internal set;}
public int SampleCount {get; internal set;}
public int Frequency {get; internal set;}

public WAV(byte[] wav)
{

// Determine if mono or stereo
ChannelCount = wav[22]; // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels

// Get the frequency
Frequency = bytesToInt(wav, 24);

// Get past all the other sub chunks to get to the data subchunk:
int pos = 12; // First Subchunk ID from 12 to 16

// Keep iterating until we find the data chunk (ie 64 61 74 61 ...... (ie 100 97 116 97 in decimal))
while (!(wav[pos] == 100 && wav[ pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3< /span>] == 97))
{
pos
+= 4;
int chunkSize = wav[pos] + wav[pos + 1< /span>] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216 ;
pos
+= 4 + chunkSize;
}
pos
+= 8;

// Pos is now positioned to start of actual sound data.< /span>
SampleCount = (wav.Length-pos) / 2; // 2 bytes per sample (16 bit sound mono)
if (ChannelCount == 2) SampleCount /= 2; // 4 bytes per sample (16 bit stereo)

// Allocate memory (right will be null if only mono sound)
LeftChannel = new float[SampleCount];
if (ChannelCount == 2) RightChannel = < span style="color: #0000ff;">new
float[SampleCount];
else RightChannel = null;

// Write to double array/s:
int i = 0;
int maxInput = wav.Length-(RightChannel == null span>? 1: 3 );
// while (pos
while ((i maxInput))
{
LeftChannel[i]
= bytesToFloat(wav[pos], wav[pos + 1]);
pos
+= 2;
if (ChannelCount == 2)
{
RightChannel[i]
= bytesToFloat(wav[pos], wav[pos + 1]);
pos
+= 2;
}
i
++;
}
}

public override string ToString()
{
return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3} , Frequency={4}]", LeftChannel,
RightChannel, ChannelCount, SampleCount, Frequency);
}
}

Hang another AudioSource, read the file simply and roughly, decode it into byte[], fill it into AudioClip, and play it.

void PlayOGG()

{
string path = Application.dataPath + "/../Audio/Music/a.ogg";
byte[] data = File.ReadAllBytes(path);
audioSource.clip
= NAudioPlayer.FromOggData(data);
audioSource.Play();
}
void PlayMP3()
{
string path = Application.dataPath + "/../Audio/Music/a.mp3";
byte[] data = File.ReadAllBytes(path);
audioSource.clip
= NAudioPlayer.FromMp3Data(data);
audioSource.Play();
}
void PlayWAV()
{
string path = Application.dataPath + "/../Audio/Music/a.wav";
byte[] data = File.ReadAllBytes(path);
audioSource.clip
= NAudioPlayer.FromWavData(data);
audioSource.Play();
}

Install-Package NAudio.Vorbis  

< /p>

using UnityEngine;

using System.IO;
using System;
using NAudio;
using NAudio.Wave;

public static class NAudioPlayer
{
static NVorbis.VorbisReader vorbis;
public static AudioClip FromOggData(byte[] data)
{
// Load the data into a stream
MemoryStream oggstream = new MemoryStream(data);

vorbis
= new NVorbis.VorbisReader(oggstream, false );

int samplecount = (int)(vorbis.SampleRate * vorbis.TotalTime.TotalSeconds);

// AudioClip audioClip = AudioClip.Create("clip", samplecount , vorbis.Channels, vorbis.SampleRate, false, true, OnAudioRead, OnAudioSetPosition);
AudioClip audioClip = AudioClip.Create("ogg clip", samplecount, vorbis.Channels, vorbis.SampleRate, false, OnAudioRead);
// Return the clip
return audioClip;
}
static void OnAudioRead(float[] data)
{
var f = new float[data.Length];
vorbis.ReadSamples(f,
0, data.Length);
for (int i = 0; i )
{
data[i] = f[i];
}
}
static void OnAudioSetPosition(int newPosition)
{
vorbis.DecodedTime
= new TimeSpan(newPosition); //Only used to rewind the stream, we won't be seeking
}
public static AudioClip FromWavData(byte[] data)
{
WAV wav
= new WAV(data);
AudioClip audioClip
= AudioClip.Create("wavClip< span style="color: #800000;">"
, wav.SampleCount, 1, wav.Frequency, false);
audioClip.SetData(wav.LeftChannel,
0);
return audioClip;
}
public static AudioClip FromMp3Data(byte[] data)
{
// Load the data into a stream
MemoryStream mp3stream = new MemoryStream(data);
// Convert the data in the stream to WAV format
Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);
WaveStream waveStream
= WaveFormatConversionStream.CreatePcmStream(mp3audio);
// Convert to WAV data
WAV wav = new WAV(AudioMemStream(waveStream).ToArray());
Debug.Log(wav);
AudioClip audioClip
= AudioClip.Create("mp3Clip< span style="color: #800000;">", wav.SampleCount, 1, wav.Frequency, false);
audioClip.SetData(wav.LeftChannel,
0);
// Return the clip
return audioClip;
}

private static MemoryStream AudioMemStream(WaveStream waveStream)
{
MemoryStream outputStream
= new MemoryStream();
using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Position
= 0;
waveStream.Read(bytes,
0, Convert.ToInt32(waveStream. Length));
waveFileWriter.Write(bytes,
0, bytes.Length);
waveFileWriter.Flush();
}
return outputStream;
}
}

/* From http://answers.unity3d.com/questions/737002/wav-byte-to-audioclip.html */
public class WAV
{

// convert two bytes to one float in the range -1 to 1
static float bytesToFloat(byte firstByte, byte secondByte)
{
// convert two bytes to one short (little endian) span>
short s = (short)((secondByte << 8) | firstByte);
// convert to range from -1 to (just below) 1
return s / 32768.0F;
}

static int bytesToInt(byte[] bytes, int offset = 0)
{
int value = 0;
for (int i = 0; i <4; i++)
{
value
|= ((int)bytes[offset + i]) << (i * 8);
}
return value;
}
// properties
public float[] LeftChannel { get; internal set; }
public float[] RightChannel { get; internal set; }
public int ChannelCount { get; internal set; }
public int SampleCount { get; internal set; }
public int Frequency { get; internal set; }

public WAV(byte[] wav)
{

// Determine if mono or stereo
ChannelCount = wav[22]; // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels

// Get the frequency
Frequency = bytesToInt(wav, 24);

// Get past all the other sub chunks to get to the data subchunk:
int pos = 12; // First Subchunk ID from 12 to 16

// Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))
while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97))
{
pos
+= 4;
int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
pos
+= 4 + chunkSize;
}
pos
+= 8;

// Pos is now positioned to start of actual sound data.
SampleCount = (wav.Length - pos) / 2; // 2 bytes per sample (16 bit sound mono)
if (ChannelCount == 2) SampleCount /= 2; // 4 bytes per sample (16 bit stereo)

// Allocate memory (right will be null if only mono sound)
LeftChannel = new float[SampleCount];
if (ChannelCount == 2) RightChannel = new float[SampleCount];
else RightChannel = null;

// Write to double array/s:
int i = 0;
int maxInput = wav.Length - (RightChannel == null ? 1 : 3);
// while (pos < wav.Length)
while ((i < SampleCount) && (pos < maxInput))
{
LeftChannel[i]
= bytesToFloat(wav[pos], wav[pos + 1]);
pos
+= 2;
if (ChannelCount == 2)
{
RightChannel[i]
= bytesToFloat(wav[pos], wav[pos + 1]);
pos
+= 2;
}
i
++;
}
}

public override string ToString()
{
return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel,
RightChannel, ChannelCount, SampleCount, Frequency);
}
}

void PlayOGG()

{
string path = Application.dataPath + "/../Audio/Music/a.ogg";
byte[] data = File.ReadAllBytes(path);
audioSource.clip
= NAudioPlayer.FromOggData(data);
audioSource.Play();
}
void PlayMP3()
{
string path = Application.dataPath + "/../Audio/Music/a.mp3";
byte[] data = File.ReadAllBytes(path);
audioSource.clip
= NAudioPlayer.FromMp3Data(data);
audioSource.Play();
}
void PlayWAV()
{
string path = Application.dataPath + "/../Audio/Music/a.wav";
byte[] data = File.ReadAllBytes(path);
audioSource.clip
= NAudioPlayer.FromWavData(data);
audioSource.Play();
}

Leave a Comment

Your email address will not be published.