Initial sound impl
This commit is contained in:
7
Ryuclaw.Audio.Shared/Class1.cs
Normal file
7
Ryuclaw.Audio.Shared/Class1.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryuclaw.Audio.Shared;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
9
Ryuclaw.Audio.Shared/Ryuclaw.Audio.Shared.csproj
Normal file
9
Ryuclaw.Audio.Shared/Ryuclaw.Audio.Shared.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
24
Ryuclaw.Audio.Shared/WaveHeader.cs
Normal file
24
Ryuclaw.Audio.Shared/WaveHeader.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
namespace Ryuclaw.Audio.Shared
|
||||
{
|
||||
public class WaveHeader
|
||||
{
|
||||
public int SampleRate { get; private set; }
|
||||
public int ChunkSize { get; private set; }
|
||||
public int ByteRate { get; private set; }
|
||||
public short BitsPerSample { get; private set; }
|
||||
public short NumChannels { get; private set; }
|
||||
public short BlockAlign { get; private set; }
|
||||
|
||||
public WaveHeader(int sampleRate = 48000, int chunkSize = 16, int byteRate = 16, short bitsPerSample = 16, short numChannels = 1, short blockAlign = 8)
|
||||
{
|
||||
SampleRate = sampleRate;
|
||||
ChunkSize = chunkSize;
|
||||
ByteRate = byteRate;
|
||||
BitsPerSample = bitsPerSample;
|
||||
NumChannels = numChannels;
|
||||
BlockAlign = blockAlign;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
57
Ryuclaw.Audio.Shared/WaveReader.cs
Normal file
57
Ryuclaw.Audio.Shared/WaveReader.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryuclaw.Audio.Shared
|
||||
{
|
||||
public class WaveReader
|
||||
{
|
||||
private WaveHeader _header;
|
||||
public byte[] AudioData { get; private set; }
|
||||
|
||||
public WaveReader()
|
||||
{
|
||||
_header = new WaveHeader();
|
||||
AudioData = new byte[0];
|
||||
}
|
||||
|
||||
public void Load(string filePath)
|
||||
{
|
||||
using (var stream = new FileStream(filePath, FileMode.Open))
|
||||
using (var reader = new BinaryReader(stream))
|
||||
{
|
||||
// RIFF header
|
||||
string chunkID = new string(reader.ReadChars(4));
|
||||
if (chunkID != "RIFF") throw new Exception("Not a valid WAV file.");
|
||||
|
||||
var ChunkSize = reader.ReadInt32(); // Chunk size
|
||||
string format = new string(reader.ReadChars(4));
|
||||
if (format != "WAVE") throw new Exception("Not a valid WAV file.");
|
||||
|
||||
// fmt sub-chunk
|
||||
string subchunk1ID = new string(reader.ReadChars(4));
|
||||
if (subchunk1ID != "fmt ") throw new Exception("Expected fmt chunk.");
|
||||
|
||||
int subChunk1Size = reader.ReadInt32();
|
||||
short audioFormat = reader.ReadInt16();
|
||||
var NumChannels = reader.ReadInt16();
|
||||
var SampleRate = reader.ReadInt32();
|
||||
var ByteRate = reader.ReadInt32(); // Byte rate
|
||||
var BlockAlign = reader.ReadInt16(); // Block align
|
||||
var BitsPerSample = reader.ReadInt16();
|
||||
_header = new WaveHeader(SampleRate, ChunkSize, ByteRate, BitsPerSample, NumChannels, BlockAlign);
|
||||
if (audioFormat != 1 || subChunk1Size != 16)
|
||||
{
|
||||
throw new Exception("Only PCM format WAV files are supported.");
|
||||
}
|
||||
|
||||
// data sub-chunk
|
||||
string subchunk2ID = new string(reader.ReadChars(4));
|
||||
if (subchunk2ID != "data") throw new Exception("Expected data chunk.");
|
||||
|
||||
int subChunk2Size = reader.ReadInt32();
|
||||
AudioData = reader.ReadBytes(subChunk2Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
79
Ryuclaw.Audio.Shared/WaveStreamer.cs
Normal file
79
Ryuclaw.Audio.Shared/WaveStreamer.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryuclaw.Audio.Shared
|
||||
{
|
||||
public class WaveStreamer : IDisposable
|
||||
{
|
||||
private readonly FileStream _fileStream;
|
||||
private readonly BinaryReader _reader;
|
||||
|
||||
private long _dataPosition; // This will store the position where audio data begins in the file.
|
||||
private int _dataLength; // This will store the length of the audio data.
|
||||
|
||||
private WaveHeader _header;
|
||||
|
||||
public WaveStreamer(string filePath)
|
||||
{
|
||||
_header = new WaveHeader();
|
||||
_fileStream = new FileStream(filePath, FileMode.Open);
|
||||
_reader = new BinaryReader(_fileStream);
|
||||
LoadHeader();
|
||||
}
|
||||
|
||||
private void LoadHeader()
|
||||
{
|
||||
// RIFF header
|
||||
string chunkID = new string(_reader.ReadChars(4));
|
||||
if (chunkID != "RIFF") throw new Exception("Not a valid WAV file.");
|
||||
|
||||
var ChunkSize = _reader.ReadInt32(); // Chunk size
|
||||
string format = new string(_reader.ReadChars(4));
|
||||
if (format != "WAVE") throw new Exception("Not a valid WAV file.");
|
||||
|
||||
// fmt sub-chunk
|
||||
string subchunk1ID = new string(_reader.ReadChars(4));
|
||||
if (subchunk1ID != "fmt ") throw new Exception("Expected fmt chunk.");
|
||||
|
||||
int subChunk1Size = _reader.ReadInt32();
|
||||
short audioFormat = _reader.ReadInt16();
|
||||
var NumChannels = _reader.ReadInt16();
|
||||
var SampleRate = _reader.ReadInt32();
|
||||
var ByteRate = _reader.ReadInt32(); // Byte rate
|
||||
var BlockAlign = _reader.ReadInt16(); // Block align
|
||||
var BitsPerSample = _reader.ReadInt16();
|
||||
_header = new WaveHeader(SampleRate, ChunkSize, ByteRate, BitsPerSample, NumChannels, BlockAlign);
|
||||
if (audioFormat != 1 || subChunk1Size != 16)
|
||||
{
|
||||
throw new Exception("Only PCM format WAV files are supported.");
|
||||
}
|
||||
|
||||
// data sub-chunk
|
||||
string subchunk2ID = new string(_reader.ReadChars(4));
|
||||
if (subchunk2ID != "data") throw new Exception("Expected data chunk.");
|
||||
|
||||
_dataLength = _reader.ReadInt32();
|
||||
_dataPosition = _fileStream.Position; // Store the position where audio data begins.
|
||||
}
|
||||
|
||||
public byte[] ReadData(int byteCount)
|
||||
{
|
||||
_fileStream.Seek(_dataPosition, SeekOrigin.Begin);
|
||||
byte[] buffer = _reader.ReadBytes(byteCount); // Read a chunk of audio data.
|
||||
_dataPosition = _fileStream.Position; // Update the position to start from next time.
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public bool HasDataLeft()
|
||||
{
|
||||
return _fileStream.Position < _dataPosition + _dataLength;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_reader.Dispose();
|
||||
_fileStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user