Skip to content

Commit

Permalink
Upgraded to .NET 8 and made code style a little more internally consi…
Browse files Browse the repository at this point in the history
…stent. (#1680)
  • Loading branch information
Lamothe authored Jan 4, 2025
1 parent bf3330c commit 8a60985
Show file tree
Hide file tree
Showing 29 changed files with 335 additions and 385 deletions.
2 changes: 1 addition & 1 deletion dotnet-examples/Common/Common.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
Expand Down
281 changes: 138 additions & 143 deletions dotnet-examples/Common/WaveHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,171 +4,166 @@

using System.Runtime.InteropServices;

namespace SherpaOnnx
{
namespace SherpaOnnx;

[StructLayout(LayoutKind.Sequential)]
public struct WaveHeader
[StructLayout(LayoutKind.Sequential)]
public struct WaveHeader
{
public int ChunkID;
public int ChunkSize;
public int Format;
public int SubChunk1ID;
public int SubChunk1Size;
public short AudioFormat;
public short NumChannels;
public int SampleRate;
public int ByteRate;
public short BlockAlign;
public short BitsPerSample;
public int SubChunk2ID;
public int SubChunk2Size;

public bool Validate()
{
public Int32 ChunkID;
public Int32 ChunkSize;
public Int32 Format;
public Int32 SubChunk1ID;
public Int32 SubChunk1Size;
public Int16 AudioFormat;
public Int16 NumChannels;
public Int32 SampleRate;
public Int32 ByteRate;
public Int16 BlockAlign;
public Int16 BitsPerSample;
public Int32 SubChunk2ID;
public Int32 SubChunk2Size;

public bool Validate()
if (ChunkID != 0x46464952)
{
Console.WriteLine($"Invalid chunk ID: 0x{ChunkID:X}. Expect 0x46464952");
return false;
}

// E V A W
if (Format != 0x45564157)
{
Console.WriteLine($"Invalid format: 0x{Format:X}. Expect 0x45564157");
return false;
}

// t m f
if (SubChunk1ID != 0x20746d66)
{
Console.WriteLine($"Invalid SubChunk1ID: 0x{SubChunk1ID:X}. Expect 0x20746d66");
return false;
}

if (SubChunk1Size != 16)
{
Console.WriteLine($"Invalid SubChunk1Size: {SubChunk1Size}. Expect 16");
return false;
}

if (AudioFormat != 1)
{
Console.WriteLine($"Invalid AudioFormat: {AudioFormat}. Expect 1");
return false;
}

if (NumChannels != 1)
{
Console.WriteLine($"Invalid NumChannels: {NumChannels}. Expect 1");
return false;
}

if (ByteRate != (SampleRate * NumChannels * BitsPerSample / 8))
{
Console.WriteLine($"Invalid byte rate: {ByteRate}.");
return false;
}

if (BlockAlign != (NumChannels * BitsPerSample / 8))
{
if (ChunkID != 0x46464952)
{
Console.WriteLine($"Invalid chunk ID: 0x{ChunkID:X}. Expect 0x46464952");
return false;
}

// E V A W
if (Format != 0x45564157)
{
Console.WriteLine($"Invalid format: 0x{Format:X}. Expect 0x45564157");
return false;
}

// t m f
if (SubChunk1ID != 0x20746d66)
{
Console.WriteLine($"Invalid SubChunk1ID: 0x{SubChunk1ID:X}. Expect 0x20746d66");
return false;
}

if (SubChunk1Size != 16)
{
Console.WriteLine($"Invalid SubChunk1Size: {SubChunk1Size}. Expect 16");
return false;
}

if (AudioFormat != 1)
{
Console.WriteLine($"Invalid AudioFormat: {AudioFormat}. Expect 1");
return false;
}

if (NumChannels != 1)
{
Console.WriteLine($"Invalid NumChannels: {NumChannels}. Expect 1");
return false;
}

if (ByteRate != (SampleRate * NumChannels * BitsPerSample / 8))
{
Console.WriteLine($"Invalid byte rate: {ByteRate}.");
return false;
}

if (BlockAlign != (NumChannels * BitsPerSample / 8))
{
Console.WriteLine($"Invalid block align: {ByteRate}.");
return false;
}

if (BitsPerSample != 16)
{ // we support only 16 bits per sample
Console.WriteLine($"Invalid bits per sample: {BitsPerSample}. Expect 16");
return false;
}

return true;
Console.WriteLine($"Invalid block align: {ByteRate}.");
return false;
}

if (BitsPerSample != 16)
{ // we support only 16 bits per sample
Console.WriteLine($"Invalid bits per sample: {BitsPerSample}. Expect 16");
return false;
}

return true;
}
}

// It supports only 16-bit, single channel WAVE format.
// The sample rate can be any value.
public class WaveReader
// It supports only 16-bit, single channel WAVE format.
// The sample rate can be any value.
public class WaveReader
{
public WaveReader(string fileName)
{
public WaveReader(String fileName)
if (!File.Exists(fileName))
{
if (!File.Exists(fileName))
{
throw new ApplicationException($"{fileName} does not exist!");
}

using (var stream = File.Open(fileName, FileMode.Open))
{
using (var reader = new BinaryReader(stream))
{
_header = ReadHeader(reader);

if (!_header.Validate())
{
throw new ApplicationException($"Invalid wave file ${fileName}");
}

SkipMetaData(reader);

// now read samples
// _header.SubChunk2Size contains number of bytes in total.
// we assume each sample is of type int16
byte[] buffer = reader.ReadBytes(_header.SubChunk2Size);
short[] samples_int16 = new short[_header.SubChunk2Size / 2];
Buffer.BlockCopy(buffer, 0, samples_int16, 0, buffer.Length);

_samples = new float[samples_int16.Length];

for (var i = 0; i < samples_int16.Length; ++i)
{
_samples[i] = samples_int16[i] / 32768.0F;
}
}
}
throw new ApplicationException($"{fileName} does not exist!");
}

private static WaveHeader ReadHeader(BinaryReader reader)
{
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(WaveHeader)));
using var stream = File.Open(fileName, FileMode.Open);
using var reader = new BinaryReader(stream);

GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
WaveHeader header = (WaveHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(WaveHeader))!;
handle.Free();
_header = ReadHeader(reader);

return header;
if (!_header.Validate())
{
throw new ApplicationException($"Invalid wave file ${fileName}");
}

private void SkipMetaData(BinaryReader reader)
SkipMetaData(reader);

// now read samples
// _header.SubChunk2Size contains number of bytes in total.
// we assume each sample is of type int16
var buffer = reader.ReadBytes(_header.SubChunk2Size);
var samples_int16 = new short[_header.SubChunk2Size / 2];
Buffer.BlockCopy(buffer, 0, samples_int16, 0, buffer.Length);

_samples = new float[samples_int16.Length];

for (var i = 0; i < samples_int16.Length; ++i)
{
var bs = reader.BaseStream;

Int32 subChunk2ID = _header.SubChunk2ID;
Int32 subChunk2Size = _header.SubChunk2Size;

while (bs.Position != bs.Length && subChunk2ID != 0x61746164)
{
bs.Seek(subChunk2Size, SeekOrigin.Current);
subChunk2ID = reader.ReadInt32();
subChunk2Size = reader.ReadInt32();
}
_header.SubChunk2ID = subChunk2ID;
_header.SubChunk2Size = subChunk2Size;
_samples[i] = samples_int16[i] / 32768.0F;
}
}

private WaveHeader _header;
private static WaveHeader ReadHeader(BinaryReader reader)
{
var bytes = reader.ReadBytes(Marshal.SizeOf(typeof(WaveHeader)));

GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
WaveHeader header = (WaveHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(WaveHeader))!;
handle.Free();

return header;
}

// Samples are normalized to the range [-1, 1]
private float[] _samples;
private void SkipMetaData(BinaryReader reader)
{
var bs = reader.BaseStream;

public int SampleRate => _header.SampleRate;
public float[] Samples => _samples;
var subChunk2ID = _header.SubChunk2ID;
var subChunk2Size = _header.SubChunk2Size;

public static void Test(String fileName)
while (bs.Position != bs.Length && subChunk2ID != 0x61746164)
{
WaveReader reader = new WaveReader(fileName);
Console.WriteLine($"samples length: {reader.Samples.Length}");
Console.WriteLine($"samples rate: {reader.SampleRate}");
bs.Seek(subChunk2Size, SeekOrigin.Current);
subChunk2ID = reader.ReadInt32();
subChunk2Size = reader.ReadInt32();
}
_header.SubChunk2ID = subChunk2ID;
_header.SubChunk2Size = subChunk2Size;
}

private WaveHeader _header;

// Samples are normalized to the range [-1, 1]
private float[] _samples;

public int SampleRate => _header.SampleRate;

public float[] Samples => _samples;

public static void Test(string fileName)
{
WaveReader reader = new WaveReader(fileName);
Console.WriteLine($"samples length: {reader.Samples.Length}");
Console.WriteLine($"samples rate: {reader.SampleRate}");
}
}
12 changes: 5 additions & 7 deletions dotnet-examples/keyword-spotting-from-files/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
// dotnet run

using SherpaOnnx;
using System.Collections.Generic;
using System;

class KeywordSpotterDemo
{
Expand All @@ -38,11 +36,11 @@ static void Main(string[] args)

var filename = "./sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01/test_wavs/3.wav";

WaveReader waveReader = new WaveReader(filename);
var waveReader = new WaveReader(filename);

Console.WriteLine("----------Use pre-defined keywords----------");

OnlineStream s = kws.CreateStream();
var s = kws.CreateStream();
s.AcceptWaveform(waveReader.SampleRate, waveReader.Samples);

float[] tailPadding = new float[(int)(waveReader.SampleRate * 0.3)];
Expand All @@ -53,7 +51,7 @@ static void Main(string[] args)
{
kws.Decode(s);
var result = kws.GetResult(s);
if (result.Keyword != "")
if (result.Keyword != string.Empty)
{
Console.WriteLine("Detected: {0}", result.Keyword);
}
Expand All @@ -70,7 +68,7 @@ static void Main(string[] args)
{
kws.Decode(s);
var result = kws.GetResult(s);
if (result.Keyword != "")
if (result.Keyword != string.Empty)
{
Console.WriteLine("Detected: {0}", result.Keyword);
}
Expand All @@ -89,7 +87,7 @@ static void Main(string[] args)
{
kws.Decode(s);
var result = kws.GetResult(s);
if (result.Keyword != "")
if (result.Keyword != string.Empty)
{
Console.WriteLine("Detected: {0}", result.Keyword);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>keyword_spotting_from_files</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down
Loading

0 comments on commit 8a60985

Please sign in to comment.