using System; using System.Collections.Generic; using System.IO; using Godot; using NAudio.Wave; namespace AudioEditor; public partial class AudioFileAnalyzer : Node { public static AudioFileAnalyzer Instance { get; private set; } public override void _Ready() { base._Ready(); Instance = this; } public void AnalyzeFile(string path, out WaveformInfo waveformInfo) { waveformInfo = new(); if (_waveformInfoCache.ContainsKey(path)) { waveformInfo = _waveformInfoCache[path]; return; } var ext = Path.GetExtension(path); switch (ext) { case ".wav": GD.Print("Analyzing a WAV file..."); AnalyzeWav(path, out waveformInfo); break; default: GD.Print($"Format {ext} is not supported!"); break; } _waveformInfoCache.Add(path, waveformInfo); } public bool TryGetFromCache(string path, out WaveformInfo waveformInfo) { return _waveformInfoCache.TryGetValue(path, out waveformInfo); } private void AnalyzeWav(string path, out WaveformInfo waveformInfo) { waveformInfo = new WaveformInfo(); using (var reader = new WaveFileReader(path)) { waveformInfo.Length = reader.TotalTime; waveformInfo.SampleRate = reader.WaveFormat.SampleRate; long sampleCount = reader.Length / reader.WaveFormat.BlockAlign; waveformInfo.Samples = new float[sampleCount]; // Render the waveform byte[] buffer = new byte[reader.WaveFormat.BlockAlign]; for (int i = 0; i < sampleCount; i++) { int sampleIndex = i * reader.WaveFormat.BlockAlign; while (reader.Position < reader.Length) { // Read the raw bytes for the current sample reader.Read(buffer, 0, buffer.Length); // Convert the byte array to a 16-bit sample short sample = BitConverter.ToInt16(buffer, 0); waveformInfo.Samples[sampleIndex++] = (float)sample / short.MaxValue; } } } } private Dictionary _waveformInfoCache = new(); } public class WaveformInfo { public int SampleRate { get; set; } public TimeSpan Length { get; set; } public float[] Samples { get; set; } }