Loading TestV/Playgrounds/ImageAudio.cs 0 → 100644 +117 −0 Original line number Diff line number Diff line using NAudio.Wave; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using Spectre.Console; using TestV.Tools; namespace TestV.Playgrounds; public class ImageAudio : IPlayground { public string LaunchCmd { get; } = "ia"; public string? Name { get; } = "Image Audio"; public string? Description { get; } = "将32位像素转换成音频采样"; public async Task Run(string[] args) { if (Errors.ValidArgsLength(args, 1)) { } if (!File.Exists(args[0])) { AnsiConsole.MarkupLine("[red]文件不存在。[/]"); return; } var sample = ToSample(Image.Load<Rgba32>(args[0])); Console.WriteLine($"SAMPLE: {sample.Length}"); PlayFloatArray(sample, 44100, 1); } public static void PlayFloatArray(float[] samples, int sampleRate, int channels) { // 1. 将 float[] 转换为 byte[] byte[] buffer = new byte[samples.Length * sizeof(float)]; Buffer.BlockCopy(samples, 0, buffer, 0, buffer.Length); // 2. 创建 RawSourceWaveStream(指定 32-bit Float 格式) var waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); using var stream = new MemoryStream(buffer); using var rawStream = new RawSourceWaveStream(stream, waveFormat); // 3. 播放 using var outputDevice = new WaveOutEvent(); outputDevice.Init(rawStream); outputDevice.Play(); // 等待播放完成 while (outputDevice.PlaybackState == PlaybackState.Playing) { Thread.Sleep(100); } } private float[] ToSample(Image<Rgba32> image) { Console.WriteLine($"w: {image.Width}, h: {image.Height}"); var list = new List<float>(); foreach (var pixel in GetPixels(image)) { list.AddRange(PixelToSample(pixel)); } return list.ToArray(); } public static Rgba32[] GetPixels(Image<Rgba32> image) { int width = image.Width; int height = image.Height; var pixels = new Rgba32[width * height]; image.ProcessPixelRows(accessor => { for (int y = 0; y < height; y++) { Span<Rgba32> row = accessor.GetRowSpan(y); // 将整行像素拷贝到数组对应位置 row.CopyTo(pixels.AsSpan(y * width, width)); } }); return pixels; } private float[] PixelToSample(Rgba32 pixel) { var arr = new float[32]; Array.Copy(ChannelToSample(pixel.R), 0, arr, 0, 8); Array.Copy(ChannelToSample(pixel.G), 0, arr, 8, 8); Array.Copy(ChannelToSample(pixel.B), 0, arr, 16, 8); Array.Copy(ChannelToSample(pixel.A), 0, arr, 24, 8); return arr; } private float[] ChannelToSample(byte channel) { return [ GetBit(channel, 0), GetBit(channel, 1), GetBit(channel, 2), GetBit(channel, 3), GetBit(channel, 4), GetBit(channel, 5), GetBit(channel, 6), GetBit(channel, 7), GetBit(channel, 7), ]; } private float GetBit(byte value, int n) => ((value >> n & 1) != 0) ? 1f : 0f; } No newline at end of file TestV/Program.cs +4 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,10 @@ class Program .Add<ArraySpan>() .Add<MsPinyinAnalysis>() .Add<FrameworkDetect>() .Add<EEEnum>() .Add<Factorial>() .Add<SubProgram>() .Add<ImageAudio>() .Add<Exp1>(); play.Startup(args); Loading TestV/TestV.csproj +2 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ <PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.2" /> <PackageReference Include="NAudio" Version="2.3.0" /> <PackageReference Include="RadLine" Version="0.10.0" /> <PackageReference Include="Spectre.Console" Version="0.55.2" /> Loading Loading
TestV/Playgrounds/ImageAudio.cs 0 → 100644 +117 −0 Original line number Diff line number Diff line using NAudio.Wave; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using Spectre.Console; using TestV.Tools; namespace TestV.Playgrounds; public class ImageAudio : IPlayground { public string LaunchCmd { get; } = "ia"; public string? Name { get; } = "Image Audio"; public string? Description { get; } = "将32位像素转换成音频采样"; public async Task Run(string[] args) { if (Errors.ValidArgsLength(args, 1)) { } if (!File.Exists(args[0])) { AnsiConsole.MarkupLine("[red]文件不存在。[/]"); return; } var sample = ToSample(Image.Load<Rgba32>(args[0])); Console.WriteLine($"SAMPLE: {sample.Length}"); PlayFloatArray(sample, 44100, 1); } public static void PlayFloatArray(float[] samples, int sampleRate, int channels) { // 1. 将 float[] 转换为 byte[] byte[] buffer = new byte[samples.Length * sizeof(float)]; Buffer.BlockCopy(samples, 0, buffer, 0, buffer.Length); // 2. 创建 RawSourceWaveStream(指定 32-bit Float 格式) var waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); using var stream = new MemoryStream(buffer); using var rawStream = new RawSourceWaveStream(stream, waveFormat); // 3. 播放 using var outputDevice = new WaveOutEvent(); outputDevice.Init(rawStream); outputDevice.Play(); // 等待播放完成 while (outputDevice.PlaybackState == PlaybackState.Playing) { Thread.Sleep(100); } } private float[] ToSample(Image<Rgba32> image) { Console.WriteLine($"w: {image.Width}, h: {image.Height}"); var list = new List<float>(); foreach (var pixel in GetPixels(image)) { list.AddRange(PixelToSample(pixel)); } return list.ToArray(); } public static Rgba32[] GetPixels(Image<Rgba32> image) { int width = image.Width; int height = image.Height; var pixels = new Rgba32[width * height]; image.ProcessPixelRows(accessor => { for (int y = 0; y < height; y++) { Span<Rgba32> row = accessor.GetRowSpan(y); // 将整行像素拷贝到数组对应位置 row.CopyTo(pixels.AsSpan(y * width, width)); } }); return pixels; } private float[] PixelToSample(Rgba32 pixel) { var arr = new float[32]; Array.Copy(ChannelToSample(pixel.R), 0, arr, 0, 8); Array.Copy(ChannelToSample(pixel.G), 0, arr, 8, 8); Array.Copy(ChannelToSample(pixel.B), 0, arr, 16, 8); Array.Copy(ChannelToSample(pixel.A), 0, arr, 24, 8); return arr; } private float[] ChannelToSample(byte channel) { return [ GetBit(channel, 0), GetBit(channel, 1), GetBit(channel, 2), GetBit(channel, 3), GetBit(channel, 4), GetBit(channel, 5), GetBit(channel, 6), GetBit(channel, 7), GetBit(channel, 7), ]; } private float GetBit(byte value, int n) => ((value >> n & 1) != 0) ? 1f : 0f; } No newline at end of file
TestV/Program.cs +4 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,10 @@ class Program .Add<ArraySpan>() .Add<MsPinyinAnalysis>() .Add<FrameworkDetect>() .Add<EEEnum>() .Add<Factorial>() .Add<SubProgram>() .Add<ImageAudio>() .Add<Exp1>(); play.Startup(args); Loading
TestV/TestV.csproj +2 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ <PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.2" /> <PackageReference Include="NAudio" Version="2.3.0" /> <PackageReference Include="RadLine" Version="0.10.0" /> <PackageReference Include="Spectre.Console" Version="0.55.2" /> Loading