mirror of
https://github.com/SDRSharpR/SDRSharp.git
synced 2025-12-06 03:42:01 +01:00
299 lines
6.2 KiB
C#
299 lines
6.2 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace SDRSharp.Radio.PortAudio
|
|
{
|
|
public sealed class WaveFile : IDisposable
|
|
{
|
|
private unsafe static readonly float* _lutu8;
|
|
|
|
private static readonly UnsafeBuffer _lutu8Buffer;
|
|
|
|
private unsafe static readonly float* _lut16;
|
|
|
|
private static readonly UnsafeBuffer _lut16Buffer;
|
|
|
|
private readonly Stream _stream;
|
|
|
|
private bool _isPCM;
|
|
|
|
private long _dataPos;
|
|
|
|
private short _formatTag;
|
|
|
|
private int _sampleRate;
|
|
|
|
private int _avgBytesPerSec;
|
|
|
|
private int _length;
|
|
|
|
private short _blockAlign;
|
|
|
|
private short _bitsPerSample;
|
|
|
|
private UnsafeBuffer _tempBuffer;
|
|
|
|
private byte[] _temp;
|
|
|
|
private unsafe byte* _tempPtr;
|
|
|
|
public long Position
|
|
{
|
|
get
|
|
{
|
|
return this._stream.Position - this._dataPos;
|
|
}
|
|
set
|
|
{
|
|
this._stream.Seek(value + this._dataPos, SeekOrigin.Begin);
|
|
}
|
|
}
|
|
|
|
public short FormatTag
|
|
{
|
|
get
|
|
{
|
|
return this._formatTag;
|
|
}
|
|
}
|
|
|
|
public int SampleRate
|
|
{
|
|
get
|
|
{
|
|
return this._sampleRate;
|
|
}
|
|
}
|
|
|
|
public int AvgBytesPerSec
|
|
{
|
|
get
|
|
{
|
|
return this._avgBytesPerSec;
|
|
}
|
|
}
|
|
|
|
public short BlockAlign
|
|
{
|
|
get
|
|
{
|
|
return this._blockAlign;
|
|
}
|
|
}
|
|
|
|
public short BitsPerSample
|
|
{
|
|
get
|
|
{
|
|
return this._bitsPerSample;
|
|
}
|
|
}
|
|
|
|
public int Length
|
|
{
|
|
get
|
|
{
|
|
return this._length;
|
|
}
|
|
}
|
|
|
|
unsafe static WaveFile()
|
|
{
|
|
WaveFile._lutu8Buffer = UnsafeBuffer.Create(256, 4);
|
|
WaveFile._lut16Buffer = UnsafeBuffer.Create(65536, 4);
|
|
WaveFile._lutu8 = (float*)(void*)WaveFile._lutu8Buffer;
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
WaveFile._lutu8[i] = (float)(i - 128) * 0.007874016f;
|
|
}
|
|
WaveFile._lut16 = (float*)(void*)WaveFile._lut16Buffer;
|
|
for (int j = 0; j < 65536; j++)
|
|
{
|
|
WaveFile._lut16[j] = (float)(j - 32768) * 3.051851E-05f;
|
|
}
|
|
}
|
|
|
|
~WaveFile()
|
|
{
|
|
this.Dispose();
|
|
}
|
|
|
|
public WaveFile(string fileName)
|
|
{
|
|
this._stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
this.ReadHeader();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this.Close();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
if (this._stream != null)
|
|
{
|
|
this._stream.Close();
|
|
}
|
|
}
|
|
|
|
private static string ReadChunk(BinaryReader reader)
|
|
{
|
|
byte[] array = new byte[4];
|
|
reader.Read(array, 0, array.Length);
|
|
return Encoding.ASCII.GetString(array);
|
|
}
|
|
|
|
private void ReadHeader()
|
|
{
|
|
BinaryReader binaryReader = new BinaryReader(this._stream);
|
|
if (WaveFile.ReadChunk(binaryReader) != "RIFF")
|
|
{
|
|
throw new Exception("Invalid file format");
|
|
}
|
|
binaryReader.ReadInt32();
|
|
if (WaveFile.ReadChunk(binaryReader) != "WAVE")
|
|
{
|
|
throw new Exception("Invalid file format");
|
|
}
|
|
if (WaveFile.ReadChunk(binaryReader) != "fmt ")
|
|
{
|
|
throw new Exception("Invalid file format");
|
|
}
|
|
int num = binaryReader.ReadInt32();
|
|
if (num < 16)
|
|
{
|
|
throw new Exception("Invalid file format");
|
|
}
|
|
this._formatTag = binaryReader.ReadInt16();
|
|
this._isPCM = (this._formatTag == 1);
|
|
if (binaryReader.ReadInt16() != 2)
|
|
{
|
|
throw new Exception("Invalid file format");
|
|
}
|
|
this._sampleRate = binaryReader.ReadInt32();
|
|
this._avgBytesPerSec = binaryReader.ReadInt32();
|
|
this._blockAlign = binaryReader.ReadInt16();
|
|
this._bitsPerSample = binaryReader.ReadInt16();
|
|
for (num -= 16; num > 0; num--)
|
|
{
|
|
binaryReader.ReadByte();
|
|
}
|
|
while (this._stream.Position < this._stream.Length && WaveFile.ReadChunk(binaryReader) != "data")
|
|
{
|
|
num = binaryReader.ReadInt32();
|
|
while (this._stream.Position < this._stream.Length && num > 0)
|
|
{
|
|
binaryReader.ReadByte();
|
|
num--;
|
|
}
|
|
}
|
|
if (this._stream.Position >= this._stream.Length)
|
|
{
|
|
throw new Exception("Invalid file format");
|
|
}
|
|
this._length = binaryReader.ReadInt32();
|
|
this._dataPos = this._stream.Position;
|
|
}
|
|
|
|
public unsafe void Read(Complex* iqBuffer, int length)
|
|
{
|
|
if (this._temp == null || this._temp.Length != this._blockAlign * length)
|
|
{
|
|
this._temp = new byte[this._blockAlign * length];
|
|
this._tempBuffer = UnsafeBuffer.Create(this._temp);
|
|
this._tempPtr = (byte*)(void*)this._tempBuffer;
|
|
}
|
|
int i = 0;
|
|
int num2;
|
|
for (int length2 = this._tempBuffer.Length; i < length2; i += num2)
|
|
{
|
|
int num = length2 - i;
|
|
num2 = this._stream.Read(this._temp, i, num);
|
|
if (num2 < num)
|
|
{
|
|
this._stream.Position = this._dataPos;
|
|
}
|
|
}
|
|
this.FillIQ(iqBuffer, length);
|
|
}
|
|
|
|
private unsafe void FillIQ(Complex* iqPtr, int length)
|
|
{
|
|
if (this._isPCM)
|
|
{
|
|
if (this._blockAlign == 6)
|
|
{
|
|
Int24* ptr = (Int24*)this._tempPtr;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
Complex* intPtr = iqPtr;
|
|
Int24* intPtr2 = ptr;
|
|
ptr = intPtr2 + 1;
|
|
intPtr->Real = (float)(*intPtr2) * 1.192093E-07f;
|
|
Complex* intPtr3 = iqPtr;
|
|
Int24* intPtr4 = ptr;
|
|
ptr = intPtr4 + 1;
|
|
intPtr3->Imag = (float)(*intPtr4) * 1.192093E-07f;
|
|
iqPtr++;
|
|
}
|
|
}
|
|
else if (this._blockAlign == 4)
|
|
{
|
|
short* ptr2 = (short*)this._tempPtr;
|
|
for (int j = 0; j < length; j++)
|
|
{
|
|
Complex* intPtr5 = iqPtr;
|
|
float* lut = WaveFile._lut16;
|
|
short* intPtr6 = ptr2;
|
|
ptr2 = intPtr6 + 1;
|
|
intPtr5->Real = lut[*intPtr6 + 32768];
|
|
Complex* intPtr7 = iqPtr;
|
|
float* lut2 = WaveFile._lut16;
|
|
short* intPtr8 = ptr2;
|
|
ptr2 = intPtr8 + 1;
|
|
intPtr7->Imag = lut2[*intPtr8 + 32768];
|
|
iqPtr++;
|
|
}
|
|
}
|
|
else if (this._blockAlign == 2)
|
|
{
|
|
byte* ptr3 = this._tempPtr;
|
|
for (int k = 0; k < length; k++)
|
|
{
|
|
Complex* intPtr9 = iqPtr;
|
|
float* lutu = WaveFile._lutu8;
|
|
byte* intPtr10 = ptr3;
|
|
ptr3 = intPtr10 + 1;
|
|
intPtr9->Real = lutu[(int)(*intPtr10)];
|
|
Complex* intPtr11 = iqPtr;
|
|
float* lutu2 = WaveFile._lutu8;
|
|
byte* intPtr12 = ptr3;
|
|
ptr3 = intPtr12 + 1;
|
|
intPtr11->Imag = lutu2[(int)(*intPtr12)];
|
|
iqPtr++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float* ptr4 = (float*)this._tempPtr;
|
|
for (int l = 0; l < length; l++)
|
|
{
|
|
Complex* intPtr13 = iqPtr;
|
|
float* intPtr14 = ptr4;
|
|
ptr4 = intPtr14 + 1;
|
|
intPtr13->Real = *intPtr14;
|
|
Complex* intPtr15 = iqPtr;
|
|
float* intPtr16 = ptr4;
|
|
ptr4 = intPtr16 + 1;
|
|
intPtr15->Imag = *intPtr16;
|
|
iqPtr++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|