Friday, June 13, 2025

cresh trough filtering namespaces

 

 

 

////////////Qhenomenology.Waveform Analyzer

////////////-------------------------------

////////////- Target: .NET Framework 4.8, C# 7.0

////////////- Usage: Load 8000Hz mono 16-bit WAV file

////////////- Shows ProgressBar while processing

////////////- Detects waveform crests/troughs using vector turning

////////////- Classifies waveform shape using angle bins and microsecond resolution

////////////- Generates data segments with metadata for CSV exportusing System;

////////////using System.Collections.Generic;

////////////using System.Windows.Forms;

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class WaveformAnalyzer

//////    {

//////        private readonly float[] samples;

//////        private readonly int sampleRate;

//////        private readonly ProgressBar progressBar;

//////        private readonly List<WaveSegment> segments = new List<WaveSegment>();

 

 

 

 

 

 

 

 

 

//////        public WaveformAnalyzer(float[] samples, int sampleRate, ref ProgressBar progressBar)

//////        {

//////            this.samples = samples;

//////            this.sampleRate = sampleRate;

//////            this.progressBar = progressBar;

//////        }//public WaveformAnalyzer(float[] samples, int sampleRate, ProgressBar progressBar)

 

//////        public List<WaveSegment> Analyze()

//////        {

//////            int samplesPerMs = sampleRate / 1000;

//////            int zeroCrossing = 0;

//////            bool inCrest = false;

//////            WaveSegment current = null;

 

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = samples.Length;

//////            progressBar.Value = 0;

 

//////            for (int i = 1; i < samples.Length - 1; i++)

//////            {

//////                if (i % 5000 == 0 && progressBar.Value < progressBar.Maximum)

//////                { progressBar.Value = i; }

 

//////                float a = samples[i - 1];

//////                float b = samples[i];

//////                float c = samples[i + 1];

 

//////                if (a <= 0 && b > 0)

//////                {

//////                    if (current != null) segments.Add(current);

//////                    current = new WaveSegment

//////                    {

//////                        StartMicrosecond = i * 1000000 / sampleRate,

//////                        IsCrest = true,

//////                        MaxAmplitude = b

//////                    };

//////                    inCrest = true;

//////                }

//////                else if (a >= 0 && b < 0)

//////                {

//////                    if (current != null) segments.Add(current);

//////                    current = new WaveSegment

//////                    {

//////                        StartMicrosecond = i * 1000000 / sampleRate,

//////                        IsCrest = false,

//////                        MinAmplitude = b

//////                    };

//////                    inCrest = false;

//////                }//END OF ELSE OF if (a <= 0 && b > 0)

 

 

 

 

//////                if (current != null)

//////                {

//////                    float v1x = 1f, v1y = b - a;

//////                    float v2x = 1f, v2y = c - b;

//////                    double angle = Math.Acos((v1x * v2x + v1y * v2y) /

//////                        (Math.Sqrt(v1x * v1x + v1y * v1y) * Math.Sqrt(v2x * v2x + v2y * v2y))) * 180 / Math.PI;

//////                    int bin = angle < 30 ? 0 : angle < 45 ? 1 : angle < 60 ? 2 : 3;

//////                    current.AngleBins[bin]++;

//////                    current.AngleChangeCount++;

 

//////                    if (inCrest && b > a && b > c) current.LocalPeaks++;

//////                    if (!inCrest && b < a && b < c) current.LocalMins++;

//////                    if (inCrest) current.MaxAmplitude = Math.Max(current.MaxAmplitude, b);

//////                    else current.MinAmplitude = Math.Min(current.MinAmplitude, b);

 

//////                    current.EndMicrosecond = i * 1000000 / sampleRate;

//////                }//if (current != null)

//////            }

 

//////            if (current != null) segments.Add(current);

//////            progressBar.Value = progressBar.Maximum;

//////            return segments;

//////        }//public List<WaveSegment> Analyze()

//////    }//public class WaveformAnalyzer

 

 

 

//////    public class WaveSegment

//////    {

//////        public int StartMicrosecond;

//////        public int EndMicrosecond;

//////        public bool IsCrest;

//////        public float MaxAmplitude;

//////        public float MinAmplitude;

//////        public int AngleChangeCount;

//////        public int[] AngleBins = new int[4]; // [0-30, 30-45, 45-60, 60-90]

//////        public int LocalPeaks;

//////        public int LocalMins;

//////    }//public class WaveSegment

 

 

 

 

 

 

 

//////    public static class WavLoader

//////    {

//////        public static float[] LoadMono16BitPcmWav(string path, out int sampleRate)

//////        {

//////            sampleRate = 8000;

//////            using (var br = new BinaryReader(File.OpenRead(path)))

//////            {

//////                string riff = new string(br.ReadChars(4));

//////                if (riff != "RIFF") throw new Exception("Invalid WAV file");

 

//////                br.ReadInt32(); // skip file size

//////                string wave = new string(br.ReadChars(4));

//////                if (wave != "WAVE") throw new Exception("Invalid WAV file");

 

//////                string fmt = new string(br.ReadChars(4));

//////                if (fmt != "fmt ") throw new Exception("Expected 'fmt '");

 

//////                int fmtLength = br.ReadInt32();

//////                short audioFormat = br.ReadInt16();

//////                short numChannels = br.ReadInt16();

//////                sampleRate = br.ReadInt32();

//////                br.ReadInt32(); // byte rate

//////                br.ReadInt16(); // block align

//////                short bitsPerSample = br.ReadInt16();

 

//////                if (audioFormat != 1 || bitsPerSample != 16 || numChannels != 1)

//////                    throw new Exception("Only 16-bit mono PCM supported");

 

//////                br.BaseStream.Seek(fmtLength - 16, SeekOrigin.Current);

 

//////                string dataChunkId = new string(br.ReadChars(4));

//////                while (dataChunkId != "data")

//////                {

//////                    int chunkSize = br.ReadInt32();

//////                    br.BaseStream.Seek(chunkSize, SeekOrigin.Current);

//////                    dataChunkId = new string(br.ReadChars(4));

//////                }//while (dataChunkId != "data")

 

//////                int dataSize = br.ReadInt32();

//////                int numSamples = dataSize / 2;

 

//////                float[] samples = new float[numSamples];

//////                for (int i = 0; i < numSamples; i++)

//////                { samples[i] = br.ReadInt16() / 32768f; }

 

//////                return samples;

//////            }//using (var br = new BinaryReader(File.OpenRead(path)))

//////        }//public static float[] LoadMono16BitPcmWav(string path, out int sampleRate)

//////    }//public static class WavLoader

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

///

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////namespace DISCARDING___SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class WaveformAnalyzer

//////    {

//////        private readonly float[] samples;

//////        private readonly int sampleRate;

//////        private readonly ProgressBar progressBar;

//////        private readonly List<WaveSegment> segments = new List<WaveSegment>();

 

//////        public WaveformAnalyzer(float[] samples, int sampleRate, ref ProgressBar progressBar)

//////        {

//////            this.samples = samples;

//////            this.sampleRate = sampleRate;

//////            this.progressBar = progressBar;

//////        }

 

//////        public List<WaveSegment> Analyze()

//////        {

//////            int totalSamples = samples.Length;

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = totalSamples;

//////            progressBar.Value = 0;

 

//////            int samplesPerMs = sampleRate / 1000;

//////            bool inCrest = false;

//////            WaveSegment current = null;

 

//////            for (int i = 1; i < totalSamples - 1; i++)

//////            {

//////                if (i % 5000 == 0)

//////                {

//////                    progressBar.Value = Math.Min(i, progressBar.Maximum);

//////                }

 

//////                float a = samples[i - 1];

//////                float b = samples[i];

//////                float c = samples[i + 1];

 

//////                // Detect zero-crossing from negative to positive: start of crest

//////                if (a <= 0 && b > 0)

//////                {

//////                    if (current != null) segments.Add(current);

//////                    current = new WaveSegment

//////                    {

//////                        StartMicrosecond = i * 1000000 / sampleRate,

//////                        IsCrest = true,

//////                        MaxAmplitude = b

//////                    };

//////                    inCrest = true;

//////                }

//////                // Detect zero-crossing from positive to negative: start of trough

//////                else if (a >= 0 && b < 0)

//////                {

//////                    if (current != null) segments.Add(current);

//////                    current = new WaveSegment

//////                    {

//////                        StartMicrosecond = i * 1000000 / sampleRate,

//////                        IsCrest = false,

//////                        MinAmplitude = b

//////                    };

//////                    inCrest = false;

//////                }

 

//////                if (current != null)

//////                {

//////                    // Angle calculation between vectors

//////                    float v1x = 1f, v1y = b - a;

//////                    float v2x = 1f, v2y = c - b;

 

//////                    double angle = Math.Acos(

//////                        (v1x * v2x + v1y * v2y) /

//////                        (Math.Sqrt(v1x * v1x + v1y * v1y) * Math.Sqrt(v2x * v2x + v2y * v2y))

//////                    ) * 180.0 / Math.PI;

 

//////                    int bin = angle < 30 ? 0 : angle < 45 ? 1 : angle < 60 ? 2 : 3;

//////                    current.AngleBins[bin]++;

//////                    current.AngleChangeCount++;

 

//////                    if (inCrest && b > a && b > c) current.LocalPeaks++;

//////                    if (!inCrest && b < a && b < c) current.LocalMins++;

 

//////                    if (inCrest) current.MaxAmplitude = Math.Max(current.MaxAmplitude, b);

//////                    else current.MinAmplitude = Math.Min(current.MinAmplitude, b);

 

//////                    current.EndMicrosecond = i * 1000000 / sampleRate;

//////                }

//////            }

 

//////            if (current != null) segments.Add(current);

//////            progressBar.Value = progressBar.Maximum;

//////            return segments;

//////        }

//////    }//public class WaveformAnalyzer

 

//////    public class WaveSegment

//////    {

//////        public int StartMicrosecond;

//////        public int EndMicrosecond;

//////        public bool IsCrest;

//////        public float MaxAmplitude;

//////        public float MinAmplitude;

//////        public int AngleChangeCount;

//////        public int[] AngleBins = new int[4]; // [0-30, 30-45, 45-60, 60-90]

//////        public int LocalPeaks;

//////        public int LocalMins;

 

//////        public string ToCsv()

//////        {

//////            return string.Join(",",

//////                StartMicrosecond,

//////                EndMicrosecond,

//////                IsCrest ? "Crest" : "Trough",

//////                MaxAmplitude.ToString("F5"),

//////                MinAmplitude.ToString("F5"),

//////                AngleChangeCount,

//////                string.Join("|", AngleBins),

//////                LocalPeaks,

//////                LocalMins

//////            );

//////        }

//////    }// public class WaveSegment

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////    public static class WavLoader

//////    {

//////        public static float[][] LoadPcmWav(string path, out int sampleRate, out bool isStereo)

//////        {

//////            sampleRate = 8000;

//////            isStereo = false;

 

//////            using (var br = new BinaryReader(File.OpenRead(path)))

//////            {

//////                string riff = new string(br.ReadChars(4));

//////                if (riff != "RIFF") throw new Exception("Invalid WAV (no RIFF)");

 

//////                br.ReadInt32(); // skip file size

//////                string wave = new string(br.ReadChars(4));

//////                if (wave != "WAVE") throw new Exception("Invalid WAV (no WAVE)");

 

//////                string fmt = new string(br.ReadChars(4));

//////                if (fmt != "fmt ") throw new Exception("Expected fmt chunk");

 

//////                int fmtLen = br.ReadInt32();

//////                short format = br.ReadInt16();

//////                short channels = br.ReadInt16();

//////                sampleRate = br.ReadInt32();

//////                br.ReadInt32(); // byte rate

//////                br.ReadInt16(); // block align

//////                short bits = br.ReadInt16();

 

//////                if (format != 1 || bits != 16)

//////                    throw new Exception("Only PCM 16-bit supported");

 

//////                isStereo = (channels == 2);

 

//////                if (fmtLen > 16) br.ReadBytes(fmtLen - 16);

 

//////                // Skip to "data" chunk

//////                string chunkId = new string(br.ReadChars(4));

//////                while (chunkId != "data")

//////                {

//////                    int skip = br.ReadInt32();

//////                    br.BaseStream.Seek(skip, SeekOrigin.Current);

//////                    chunkId = new string(br.ReadChars(4));

//////                }

 

//////                int dataSize = br.ReadInt32();

//////                int totalSamples = dataSize / 2;

//////                int frames = totalSamples / channels;

 

//////                float[] left = new float[frames];

//////                float[] right = isStereo ? new float[frames] : null;

 

//////                for (int i = 0; i < frames; i++)

//////                {

//////                    left[i] = br.ReadInt16() / 32768f;

//////                    if (isStereo)

//////                        right[i] = br.ReadInt16() / 32768f;

//////                }

 

//////                return isStereo ? new[] { left, right } : new[] { left };

//////            }

//////        }

//////    }// public static class WavLoader

 

//////    public static class WavLoader___only_mono_8000sps_16bitfloats

//////    {

//////        public static float[] LoadMono16BitPcmWav(string path, out int sampleRate)

//////        {

//////            sampleRate = 8000;

 

//////            using (var br = new BinaryReader(File.OpenRead(path)))

//////            {

//////                string riff = new string(br.ReadChars(4));

//////                if (riff != "RIFF") throw new Exception("Invalid WAV file (no RIFF)");

 

//////                br.ReadInt32(); // skip chunk size

//////                string wave = new string(br.ReadChars(4));

//////                if (wave != "WAVE") throw new Exception("Invalid WAV file (no WAVE)");

 

//////                string fmt = new string(br.ReadChars(4));

//////                if (fmt != "fmt ") throw new Exception("Invalid WAV file (no fmt)");

 

//////                int fmtSize = br.ReadInt32();

//////                short format = br.ReadInt16();

//////                short channels = br.ReadInt16();

//////                sampleRate = br.ReadInt32();

 

//////                br.ReadInt32(); // byte rate

//////                br.ReadInt16(); // block align

//////                short bits = br.ReadInt16();

 

//////                if (format != 1 || channels != 1 || bits != 16)

//////                    throw new Exception("Only mono 16-bit PCM supported");

 

//////                // Skip any extra fmt bytes

//////                if (fmtSize > 16)

//////                    br.ReadBytes(fmtSize - 16);

 

//////                string dataChunkId = new string(br.ReadChars(4));

//////                while (dataChunkId != "data")

//////                {

//////                    int skip = br.ReadInt32();

//////                    br.ReadBytes(skip);

//////                    dataChunkId = new string(br.ReadChars(4));

//////                }

 

//////                int dataSize = br.ReadInt32();

//////                int numSamples = dataSize / 2;

//////                float[] samples = new float[numSamples];

//////                for (int i = 0; i < numSamples; i++)

//////                    samples[i] = br.ReadInt16() / 32768f;

 

//////                return samples;

//////            }

//////        }

//////    }//public static class WavLoader

 

 

 

 

 

 

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string outputPath, List<WaveSegment> segments)

//////        {

//////            using (var sw = new StreamWriter(outputPath))

//////            {

//////                sw.WriteLine("Start(us),End(us),Type,MaxAmp,MinAmp,AngleChanges,Bins,LocalPeaks,LocalMins");

//////                foreach (var seg in segments)

//////                    sw.WriteLine(seg.ToCsv());

//////            }

//////        }

//////    }//public static class CsvExporter

 

 

 

 

 

 

 

 

 

 

 

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// Namespace: SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////using System;

//////using System.Collections.Generic;

//////using System.ComponentModel;

//////using System.IO;

//////using System.Windows.Forms;

//////using System.Threading;

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class WaveSegment

//////    {

//////        public int StartMicrosecond;

//////        public int EndMicrosecond;

//////        public bool IsCrest;

//////        public float MaxAmplitude;

//////        public float MinAmplitude;

//////        public int AngleChangeCount;

//////        public int[] AngleBins = new int[4];

//////        public int LocalPeaks;

//////        public int LocalMins;

//////        public int Channel;

//////    }//public class WaveSegment

//////    public static class WavLoader

//////    {

//////        public static float[][] LoadPcmWav(string path, out int sampleRate, out bool isStereo)

//////        {

//////            sampleRate = 8000;

//////            isStereo = false;

 

//////            using (var br = new BinaryReader(File.OpenRead(path)))

//////            {

//////                string riff = new string(br.ReadChars(4));

//////                if (riff != "RIFF") throw new Exception("Invalid WAV (no RIFF)");

 

//////                br.ReadInt32(); // skip file size

//////                string wave = new string(br.ReadChars(4));

//////                if (wave != "WAVE") throw new Exception("Invalid WAV (no WAVE)");

 

//////                string fmt = new string(br.ReadChars(4));

//////                if (fmt != "fmt ") throw new Exception("Expected fmt chunk");

 

//////                int fmtLen = br.ReadInt32();

//////                short format = br.ReadInt16();

//////                short channels = br.ReadInt16();

//////                sampleRate = br.ReadInt32();

//////                br.ReadInt32(); // byte rate

//////                br.ReadInt16(); // block align

//////                short bits = br.ReadInt16();

 

//////                if (format != 1 || bits != 16)

//////                    throw new Exception("Only PCM 16-bit supported");

 

//////                isStereo = (channels == 2);

 

//////                if (fmtLen > 16) br.ReadBytes(fmtLen - 16);

 

//////                // Skip to "data" chunk

//////                string chunkId = new string(br.ReadChars(4));

//////                while (chunkId != "data")

//////                {

//////                    int skip = br.ReadInt32();

//////                    br.BaseStream.Seek(skip, SeekOrigin.Current);

//////                    chunkId = new string(br.ReadChars(4));

//////                }

 

//////                int dataSize = br.ReadInt32();

//////                int totalSamples = dataSize / 2;

//////                int frames = totalSamples / channels;

 

//////                float[] left = new float[frames];

//////                float[] right = isStereo ? new float[frames] : null;

 

//////                for (int i = 0; i < frames; i++)

//////                {

//////                    left[i] = br.ReadInt16() / 32768f;

//////                    if (isStereo)

//////                        right[i] = br.ReadInt16() / 32768f;

//////                }

 

//////                return isStereo ? new[] { left, right } : new[] { left };

//////            }

//////        }

//////    }// public static class WavLoader

 

 

//////    public class WaveformAnalyzer

//////    {

//////        private readonly float[][] channels;

//////        private readonly int sampleRate;

//////        private readonly ProgressBar progressBar;

//////        private readonly List<WaveSegment> segments = new List<WaveSegment>();

 

//////        //////public WaveformAnalyzer(float[][] channels, int sampleRate, ref ProgressBar progressBar)

//////        //////{

//////        //////    this.channels = channels;

//////        //////    this.sampleRate = sampleRate;

//////        //////    this.progressBar = progressBar;

//////        //////}//public WaveformAnalyzer(float[][] channels, int sampleRate, ref ProgressBar progressBar)

 

 

//////        public WaveformAnalyzer(float[][] channels, int sampleRate,  ProgressBar progressBar)

//////        {

//////            this.channels = channels;

//////            this.sampleRate = sampleRate;

//////            this.progressBar = progressBar;

//////        }//public WaveformAnalyzer(float[][] channels, int sampleRate, ref ProgressBar progressBar)

 

//////        public List<WaveSegment> Analyze()

//////        {

//////            int samples = channels[0].Length;

//////            int samplesPerMs = sampleRate / 1000;

 

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = samples;

//////            progressBar.Value = 0;

 

//////            for (int ch = 0; ch < channels.Length; ch++)

//////            {

//////                var data = channels[ch];

//////                bool inCrest = false;

//////                WaveSegment current = null;

 

//////                for (int i = 1; i < data.Length - 1; i++)

//////                {

//////                    if (ch == 0 && i % 5000 == 0 && progressBar.Value < progressBar.Maximum)

//////                        progressBar.Value = i;

 

//////                    float a = data[i - 1];

//////                    float b = data[i];

//////                    float c = data[i + 1];

 

//////                    if (a <= 0 && b > 0)

//////                    {

//////                        if (current != null) segments.Add(current);

//////                        current = new WaveSegment { StartMicrosecond = i * 1000000 / sampleRate, IsCrest = true, MaxAmplitude = b, Channel = ch };

//////                        inCrest = true;

//////                    }

//////                    else if (a >= 0 && b < 0)

//////                    {

//////                        if (current != null) segments.Add(current);

//////                        current = new WaveSegment { StartMicrosecond = i * 1000000 / sampleRate, IsCrest = false, MinAmplitude = b, Channel = ch };

//////                        inCrest = false;

//////                    }

 

//////                    if (current != null)

//////                    {

//////                        float v1x = 1f, v1y = b - a;

//////                        float v2x = 1f, v2y = c - b;

//////                        double angle = Math.Acos((v1x * v2x + v1y * v2y) / (Math.Sqrt(v1x * v1x + v1y * v1y) * Math.Sqrt(v2x * v2x + v2y * v2y))) * 180 / Math.PI;

//////                        int bin = angle < 30 ? 0 : angle < 45 ? 1 : angle < 60 ? 2 : 3;

//////                        current.AngleBins[bin]++;

//////                        current.AngleChangeCount++;

 

//////                        if (inCrest && b > a && b > c) current.LocalPeaks++;

//////                        if (!inCrest && b < a && b < c) current.LocalMins++;

//////                        if (inCrest) current.MaxAmplitude = Math.Max(current.MaxAmplitude, b);

//////                        else current.MinAmplitude = Math.Min(current.MinAmplitude, b);

 

//////                        current.EndMicrosecond = i * 1000000 / sampleRate;

//////                    }

//////                }

 

//////                if (current != null) segments.Add(current);

//////            }

 

//////            progressBar.Value = progressBar.Maximum;

//////            return segments;

//////        }

//////    }

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string path, List<WaveSegment> segments)

//////        {

//////            using (var sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("Channel,Type,StartUs,EndUs,MaxAmp,MinAmp,AngleChanges,Bin0,Bin1,Bin2,Bin3,Peaks,Mins");

//////                foreach (var s in segments)

//////                {

//////                    sw.WriteLine($"{s.Channel},{(s.IsCrest ? "Crest" : "Trough")},{s.StartMicrosecond},{s.EndMicrosecond},{s.MaxAmplitude},{s.MinAmplitude},{s.AngleChangeCount},{s.AngleBins[0]},{s.AngleBins[1]},{s.AngleBins[2]},{s.AngleBins[3]},{s.LocalPeaks},{s.LocalMins}");

//////                }

//////            }

//////        }

 

//////        public static void ExportPerMillisecond(string path, float[][] samples, int sampleRate)

//////        {

//////            using (var sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("Millisecond,Channel,AvgAmplitude");

//////                int totalMs = samples[0].Length * 1000 / sampleRate;

//////                for (int ch = 0; ch < samples.Length; ch++)

//////                {

//////                    var data = samples[ch];

//////                    for (int ms = 0; ms < totalMs; ms++)

//////                    {

//////                        int start = ms * sampleRate / 1000;

//////                        int end = Math.Min(start + sampleRate / 1000, data.Length);

//////                        float sum = 0;

//////                        for (int i = start; i < end; i++) sum += Math.Abs(data[i]);

//////                        float avg = sum / (end - start);

//////                        sw.WriteLine($"{ms},{ch},{avg:F4}");

//////                    }

//////                }

//////            }

//////        }

//////    }

 

//////    public static class WavRegenerator

//////    {

//////        public static void SaveWav(string path, float[][] channels, int sampleRate)

//////        {

//////            using (var bw = new BinaryWriter(File.Create(path)))

//////            {

//////                int samples = channels[0].Length;

//////                int channelsCount = channels.Length;

//////                int byteRate = sampleRate * channelsCount * 2;

//////                int blockAlign = channelsCount * 2;

//////                int dataSize = samples * blockAlign;

 

//////                bw.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));

//////                bw.Write(36 + dataSize);

//////                bw.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt "));

//////                bw.Write(16);

//////                bw.Write((short)1);

//////                bw.Write((short)channelsCount);

//////                bw.Write(sampleRate);

//////                bw.Write(byteRate);

//////                bw.Write((short)blockAlign);

//////                bw.Write((short)16);

//////                bw.Write(System.Text.Encoding.ASCII.GetBytes("data"));

//////                bw.Write(dataSize);

 

//////                for (int i = 0; i < samples; i++)

//////                {

//////                    for (int ch = 0; ch < channelsCount; ch++)

//////                    {

//////                        short val = (short)(Math.Max(-1f, Math.Min(1f, channels[ch][i])) * 32767);

//////                        bw.Write(val);

//////                    }

//////                }

//////            }

//////        }

//////    }

 

//////    //////public class ThreadedWaveProcessor

//////    //////{

//////    //////    //????????????progressBar.Invoke((MethodInvoker)(() => progressBar.Value = Math.Min(value, progressBar.Maximum)));

//////    //////    public void Start(string wavPath,  ProgressBar bar, Action<List<WaveSegment>> onDone)

//////    //////    {

//////    //////        BackgroundWorker bw = new BackgroundWorker();

//////    //////        bw.DoWork += (s, e) =>

//////    //////        {

//////    //////            int rate;

//////    //////            bool isStereo;

//////    //////            var samples = WavLoader.LoadPcmWav(wavPath, out rate, out isStereo);

//////    //////            //   var analyzer = new WaveformAnalyzer(samples, rate, ref bar);

//////    //////            var analyzer = new WaveformAnalyzer(samples, rate,ref  bar);

//////    //////            var result = analyzer.Analyze();

//////    //////            e.Result = result;

//////    //////        };

 

//////    //////        bw.RunWorkerCompleted += (s, e) =>

//////    //////        {

//////    //////            onDone?.Invoke(e.Result as List<WaveSegment>);

//////    //////        };

 

//////    //////        bw.RunWorkerAsync();

//////    //////    }

//////    //////}//public class ThreadedWaveProcessor

 

 

 

//////    //////public class ThreadedWaveProcessor

//////    //////{

//////    //////    public void Start(string wavPath, ProgressBar bar, Action<List<WaveSegment>> onDone)

//////    //////    {

//////    //////        BackgroundWorker bw = new BackgroundWorker();

//////    //////        bw.WorkerReportsProgress = true;

 

//////    //////        bw.DoWork += (s, e) =>

//////    //////        {

//////    //////            try

//////    //////            {

//////    //////                int sampleRate;

//////    //////                bool isStereo;

 

//////    //////                // Load stereo/mono WAV

//////    //////                float[][] samples = WavLoader.LoadPcmWav(wavPath, out sampleRate, out isStereo);

 

//////    //////                // Analyze both channels independently

//////    //////                var allSegments = new List<WaveSegment>();

 

//////    //////                for (int ch = 0; ch < samples.Length; ch++)

//////    //////                {

//////    //////                    var analyzer = new WaveformAnalyzer(samples[ch], sampleRate, bar);

//////    //////                    var segments = analyzer.Analyze();

//////    //////                    allSegments.AddRange(segments);

//////    //////                }//for (int ch = 0; ch < samples.Length; ch++)

 

//////    //////                e.Result = allSegments;

//////    //////            }

//////    //////            catch (Exception ex)

//////    //////            {

//////    //////                MessageBox.Show("Waveform analysis failed:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

//////    //////                e.Result = new List<WaveSegment>(); // return empty result on error

//////    //////            }

//////    //////        };

 

//////    //////        bw.RunWorkerCompleted += (s, e) =>

//////    //////        {

//////    //////            try

//////    //////            {

//////    //////                onDone?.Invoke(e.Result as List<WaveSegment>);

//////    //////            }

//////    //////            catch (Exception ex)

//////    //////            {

//////    //////                MessageBox.Show("Post-processing failed:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

//////    //////            }

//////    //////        };

 

//////    //////        bw.RunWorkerAsync();

//////    //////    }

//////    //////}//public class ThreadedWaveProcessor

 

 

 

//////    public class ThreadedWaveProcessor___for_mono

//////    {

//////        public void Start(string wavPath, ProgressBar bar, Action<List<WaveSegment>> onDone)

//////        {

//////            BackgroundWorker bw = new BackgroundWorker();

//////            bw.DoWork += (s, e) =>

//////            {

//////                try

//////                {

//////                    int rate;

//////                    bool isStereo;

//////                    // Assuming your current WavLoader returns float[] for mono

//////                    float[] samples = WavLoader.LoadPcmWav(wavPath, out rate, out isStereo);

 

//////                    var analyzer = new WaveformAnalyzer(samples, rate, ref bar);

//////                    var segments = analyzer.Analyze();

//////                    e.Result = segments;

//////                }

//////                catch (Exception ex)

//////                {

//////                    MessageBox.Show("Waveform analysis failed:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

//////                    e.Result = new List<WaveSegment>();

//////                }

//////            };

 

//////            bw.RunWorkerCompleted += (s, e) =>

//////            {

//////                try

//////                {

//////                    onDone?.Invoke(e.Result as List<WaveSegment>);

//////                }

//////                catch (Exception ex)

//////                {

//////                    MessageBox.Show("Post-processing failed:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

//////                }

//////            };

 

//////            bw.RunWorkerAsync();

//////        }

//////    }// public class ThreadedWaveProcessor___for_mono

 

//////    public static class DxfVisualizer

//////    {

//////        public static void DrawDxf(string path, List<WaveSegment> segments, int sampleRate)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("0\nSECTION\n2\nENTITIES");

//////                foreach (var seg in segments)

//////                {

//////                    double x1 = seg.StartMicrosecond / 1000.0;

//////                    double x2 = seg.EndMicrosecond / 1000.0;

//////                    double y = seg.Channel * 10 + (seg.IsCrest ? 5 : -5);

//////                    sw.WriteLine("0\nLINE\n8\nwave\n10\n" + x1 + "\n20\n" + y + "\n11\n" + x2 + "\n21\n" + y);

//////                }

//////                sw.WriteLine("0\nENDSEC\n0\nEOF");

//////            }

//////        }

//////    }

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

///thread safe systems disturbs

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

 

 

 

//////    public class CrestTroughSegment

//////    {

//////        public int StartIndex { get; set; }

//////        public int EndIndex { get; set; }

 

//////        public float PeakValue { get; set; }   // For crests

//////        public float MinValue { get; set; }    // For troughs

 

//////        public string Label { get; set; }      // "crest" or "trough"

 

//////        public int DurationInSamples

//////        {

//////            get { return EndIndex - StartIndex + 1; }

//////        }

 

//////        public float AverageAmplitude

//////        {

//////            get { return (Math.Abs(PeakValue) + Math.Abs(MinValue)) / 2f; }

//////        }

 

//////        public override string ToString()

//////        {

//////            return $"{Label.ToUpper()} from {StartIndex} to {EndIndex}, ΔSamples: {DurationInSamples}";

//////        }

//////    }// public class CrestTroughSegment

 

 

 

//////    public class ThreadedWaveProcessor___for_mono

//////    {

//////        public void Start(

//////            string wavFilePath,

//////            ref ProgressBar progressBar,

//////            Action<List<

//////                CrestTroughSegment

//////                >> callbackAfterProcessing)

//////        {

//////            Thread processingThread = new Thread(() =>

//////            {

//////                try

//////                {

//////                    int sampleRate;

//////                    bool isStereo;

 

//////                    float[] samples = WavLoader.LoadPcmWav(wavFilePath, out sampleRate, out isStereo);

 

//////                    if (isStereo)

//////                        throw new Exception("Stereo WAV not supported in mono processor.");

 

//////                    progressBar.Invoke((MethodInvoker)(() =>

//////                    {

//////                        progressBar.Minimum = 0;

//////                        progressBar.Maximum = samples.Length;

//////                        progressBar.Value = 0;

//////                    }));

 

//////                    List<CrestTroughSegment> segments = CrestTroughAnalyzer.AnalyzeCrestsAndTroughs(

//////                        samples, sampleRate,

//////                        ref progressBar);

 

//////                    callbackAfterProcessing?.Invoke(segments);

//////                }

//////                catch (Exception ex)

//////                {

//////                    MessageBox.Show("Error during waveform processing:\n" + ex.Message);

//////                }

//////            });

 

//////            processingThread.IsBackground = true;

//////            processingThread.Start();

//////        }

//////    }

 

//////    public class WaveSegment

//////    {

//////        public int StartMicrosecond;

//////        public int EndMicrosecond;

//////        public bool IsCrest;

//////        public float MaxAmplitude;

//////        public float MinAmplitude;

//////        public int AngleChangeCount;

//////        public int[] AngleBins = new int[4];

//////        public int LocalPeaks;

//////        public int LocalMins;

//////        public int Channel = 0;

//////    }

 

//////    public static class WavLoader

//////    {

//////        public static float[] LoadPcmWav(string path, out int sampleRate, out bool isStereo)

//////        {

//////            sampleRate = 8000;

//////            isStereo = false;

 

//////            using (var br = new BinaryReader(File.OpenRead(path)))

//////            {

//////                if (new string(br.ReadChars(4)) != "RIFF") throw new Exception("Invalid WAV (no RIFF)");

//////                br.ReadInt32(); // Skip size

//////                if (new string(br.ReadChars(4)) != "WAVE") throw new Exception("Invalid WAV (no WAVE)");

 

//////                if (new string(br.ReadChars(4)) != "fmt ") throw new Exception("Expected fmt chunk");

//////                int fmtLen = br.ReadInt32();

//////                short format = br.ReadInt16();

//////                short channels = br.ReadInt16();

//////                sampleRate = br.ReadInt32();

//////                br.ReadInt32(); // byte rate

//////                br.ReadInt16(); // block align

//////                short bits = br.ReadInt16();

//////                if (format != 1 || bits != 16) throw new Exception("Only PCM 16-bit supported");

//////                isStereo = channels == 2;

//////                if (isStereo) throw new Exception("Stereo not supported in this analyzer.");

 

//////                if (fmtLen > 16) br.ReadBytes(fmtLen - 16);

 

//////                while (new string(br.ReadChars(4)) != "data")

//////                {

//////                    int skip = br.ReadInt32();

//////                    br.BaseStream.Seek(skip, SeekOrigin.Current);

//////                }

 

//////                int dataSize = br.ReadInt32();

//////                int totalSamples = dataSize / 2;

 

//////                float[] data = new float[totalSamples];

//////                for (int i = 0; i < totalSamples; i++)

//////                    data[i] = br.ReadInt16() / 32768f;

 

//////                return data;

//////            }

//////        }

//////    }

 

//////    public class WaveformAnalyzer

//////    {

//////        private readonly float[] samples;

//////        private readonly int sampleRate;

//////        private readonly ProgressBar progressBar;

//////        private readonly List<WaveSegment> segments = new List<WaveSegment>();

 

//////        public WaveformAnalyzer(float[] samples, int sampleRate, ref ProgressBar progressBar)

//////        {

//////            this.samples = samples;

//////            this.sampleRate = sampleRate;

//////            this.progressBar = progressBar;

//////        }

 

//////        public List<WaveSegment> Analyze()

//////        {

//////            int samplesPerMs = sampleRate / 1000;

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = samples.Length;

//////            progressBar.Value = 0;

 

//////            bool inCrest = false;

//////            WaveSegment current = null;

 

//////            for (int i = 1; i < samples.Length - 1; i++)

//////            {

//////                if (i % 5000 == 0 && progressBar.Value < progressBar.Maximum)

//////                    progressBar.Invoke((MethodInvoker)(() => progressBar.Value = i));

 

//////                float a = samples[i - 1];

//////                float b = samples[i];

//////                float c = samples[i + 1];

 

//////                if (a <= 0 && b > 0)

//////                {

//////                    if (current != null) segments.Add(current);

//////                    current = new WaveSegment { StartMicrosecond = i * 1000000 / sampleRate, IsCrest = true, MaxAmplitude = b };

//////                    inCrest = true;

//////                }

//////                else if (a >= 0 && b < 0)

//////                {

//////                    if (current != null) segments.Add(current);

//////                    current = new WaveSegment { StartMicrosecond = i * 1000000 / sampleRate, IsCrest = false, MinAmplitude = b };

//////                    inCrest = false;

//////                }

 

//////                if (current != null)

//////                {

//////                    float v1x = 1f, v1y = b - a;

//////                    float v2x = 1f, v2y = c - b;

//////                    double angle = Math.Acos((v1x * v2x + v1y * v2y) /

//////                                    (Math.Sqrt(v1x * v1x + v1y * v1y) * Math.Sqrt(v2x * v2x + v2y * v2y))) * 180 / Math.PI;

//////                    int bin = angle < 30 ? 0 : angle < 45 ? 1 : angle < 60 ? 2 : 3;

//////                    current.AngleBins[bin]++;

//////                    current.AngleChangeCount++;

//////                    if (inCrest && b > a && b > c) current.LocalPeaks++;

//////                    if (!inCrest && b < a && b < c) current.LocalMins++;

//////                    if (inCrest) current.MaxAmplitude = Math.Max(current.MaxAmplitude, b);

//////                    else current.MinAmplitude = Math.Min(current.MinAmplitude, b);

//////                    current.EndMicrosecond = i * 1000000 / sampleRate;

//////                }

//////            }

 

//////            if (current != null) segments.Add(current);

//////            progressBar.Invoke((MethodInvoker)(() => progressBar.Value = progressBar.Maximum));

//////            return segments;

//////        }

//////    }

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string path, List<WaveSegment> segments)

//////        {

//////            using (var sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("Channel,Type,StartUs,EndUs,MaxAmp,MinAmp,AngleChanges,Bin0,Bin1,Bin2,Bin3,Peaks,Mins");

//////                foreach (var s in segments)

//////                    sw.WriteLine($"{s.Channel},{(s.IsCrest ? "Crest" : "Trough")},{s.StartMicrosecond},{s.EndMicrosecond},{s.MaxAmplitude},{s.MinAmplitude},{s.AngleChangeCount},{s.AngleBins[0]},{s.AngleBins[1]},{s.AngleBins[2]},{s.AngleBins[3]},{s.LocalPeaks},{s.LocalMins}");

//////            }

//////        }

 

//////        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

//////        {

//////            using (var sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("Millisecond,AvgAmplitude");

//////                int totalMs = samples.Length * 1000 / sampleRate;

//////                for (int ms = 0; ms < totalMs; ms++)

//////                {

//////                    int start = ms * sampleRate / 1000;

//////                    int end = Math.Min(start + sampleRate / 1000, samples.Length);

//////                    float sum = 0;

//////                    for (int i = start; i < end; i++) sum += Math.Abs(samples[i]);

//////                    float avg = sum / (end - start);

//////                    sw.WriteLine($"{ms},{avg:F4}");

//////                }

//////            }

//////        }

//////    }

 

//////    //////public class ThreadedWaveProcessor___for_mono

//////    //////{

//////    //////    public void Start(string wavPath, ref ProgressBar bar, Action<List<WaveSegment>> onDone)

//////    //////    {

//////    //////        BackgroundWorker bw = new BackgroundWorker();

//////    //////        bw.DoWork += (s, e) =>

//////    //////        {

//////    //////            try

//////    //////            {

//////    //////                int rate;

//////    //////                bool isStereo;

//////    //////                float[] samples = WavLoader.LoadPcmWav(wavPath, out rate, out isStereo);

//////    //////                var analyzer = new WaveformAnalyzer(samples, rate, ref bar);

//////    //////                var segments = analyzer.Analyze();

//////    //////                e.Result = segments;

//////    //////            }

//////    //////            catch (Exception ex)

//////    //////            {

//////    //////                MessageBox.Show("Waveform analysis failed:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

//////    //////                e.Result = new List<WaveSegment>();

//////    //////            }

//////    //////        };

 

//////    //////        bw.RunWorkerCompleted += (s, e) =>

//////    //////        {

//////    //////            try

//////    //////            {

//////    //////                onDone?.Invoke(e.Result as List<WaveSegment>);

//////    //////            }

//////    //////            catch (Exception ex)

//////    //////            {

//////    //////                MessageBox.Show("Post-processing failed:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

//////    //////            }

//////    //////        };

 

//////    //////        bw.RunWorkerAsync();

//////    //////    }

//////    //////}

 

//////    public static class DxfVisualizer

//////    {

//////        public static void DrawDxf(string path, List<WaveSegment> segments)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("0\nSECTION\n2\nENTITIES");

//////                foreach (var seg in segments)

//////                {

//////                    double x1 = seg.StartMicrosecond / 1000.0;

//////                    double x2 = seg.EndMicrosecond / 1000.0;

//////                    double y = seg.IsCrest ? 10 : -10;

//////                    sw.WriteLine("0\nLINE\n8\nwave\n10\n" + x1 + "\n20\n" + y + "\n11\n" + x2 + "\n21\n" + y);

//////                }

//////                sw.WriteLine("0\nENDSEC\n0\nEOF");

//////            }

//////        }

//////    }

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class CrestTroughSegment

//////    {

//////        public int StartSample;

//////        public int EndSample;

//////        public float PeakAmplitude;

//////        public bool IsCrest;

//////    }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////    public static class WavLoader

//////    {

//////        //////public static float[][] LoadPcmWav(string path, out int sampleRate, out bool stereo)

//////        //////{

//////        //////    using (var reader = new BinaryReader(File.OpenRead(path)))

//////        //////    {

//////        //////        reader.BaseStream.Seek(24, SeekOrigin.Begin);

//////        //////        sampleRate = reader.ReadInt32();

//////        //////        reader.BaseStream.Seek(22, SeekOrigin.Begin);

//////        //////        int channels = reader.ReadInt16();

//////        //////        stereo = (channels == 2);

 

//////        //////        reader.BaseStream.Seek(44, SeekOrigin.Begin);

//////        //////        List<float> left = new List<float>();

//////        //////        List<float> right = new List<float>();

 

//////        //////        while (reader.BaseStream.Position < reader.BaseStream.Length)

//////        //////        {

//////        //////            short sampleL = reader.ReadInt16();

//////        //////            left.Add(sampleL / 32768f);

//////        //////            if (stereo)

//////        //////            {

//////        //////                short sampleR = reader.ReadInt16();

//////        //////                right.Add(sampleR / 32768f);

//////        //////            }

//////        //////        }

 

//////        //////        return stereo ? new float[][] { left.ToArray(), right.ToArray() } : new float[][] { left.ToArray() };

//////        //////    }

//////        //////}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////        public static float[] LoadMonoPcmWav(string path, out int sampleRate)

//////        {

//////            using (var reader = new BinaryReader(File.OpenRead(path)))

//////            {

//////                // Read sample rate

//////                reader.BaseStream.Seek(24, SeekOrigin.Begin);

//////                sampleRate = reader.ReadInt32();

 

//////                // Ensure it's mono (1 channel)

//////                reader.BaseStream.Seek(22, SeekOrigin.Begin);

//////                int channels = reader.ReadInt16();

//////                if (channels != 1)

//////                    throw new InvalidOperationException("Only mono WAV files are supported.");

 

//////                // Seek to data section

//////                reader.BaseStream.Seek(44, SeekOrigin.Begin);

//////                List<float> samples = new List<float>();

 

//////                while (reader.BaseStream.Position < reader.BaseStream.Length)

//////                {

//////                    short sample = reader.ReadInt16(); // 16-bit PCM

//////                    samples.Add(sample / 32768f);      // Normalize to [-1, +1]

//////                }

 

//////                return samples.ToArray();

//////            }

 

 

 

 

 

 

 

//////        }//public static float[] LoadMonoPcmWav(string path, out int sampleRate)

 

 

 

 

 

 

 

 

//////    }

 

 

 

 

 

//////    public static class CrestTroughAnalyzer

//////    {

//////        public static List<CrestTroughSegment> Analyze(float[] samples)

//////        {

//////            List<CrestTroughSegment> segments = new List<CrestTroughSegment>();

 

//////            for (int i = 1; i < samples.Length - 1; i++)

//////            {

//////                bool isCrest = samples[i] > samples[i - 1] && samples[i] > samples[i + 1];

//////                bool isTrough = samples[i] < samples[i - 1] && samples[i] < samples[i + 1];

 

//////                if (isCrest || isTrough)

//////                {

//////                    segments.Add(new CrestTroughSegment

//////                    {

//////                        StartSample = i,

//////                        EndSample = i,

//////                        PeakAmplitude = samples[i],

//////                        IsCrest = isCrest

//////                    });

//////                }

//////            }

 

//////            return segments;

//////        }

//////    }

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string path, List<CrestTroughSegment> segments)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Start,End,Amplitude,Type");

//////                foreach (var seg in segments)

//////                {

//////                    writer.WriteLine($"{seg.StartSample},{seg.EndSample},{seg.PeakAmplitude},{(seg.IsCrest ? "Crest" : "Trough")}");

//////                }

//////            }

//////        }

 

//////        //////public static void ExportPerMillisecond(string path, float[][] samples, int sampleRate)

//////        //////{

//////        //////    using (StreamWriter writer = new StreamWriter(path))

//////        //////    {

//////        //////        writer.WriteLine("Millisecond,Amplitude");

//////        //////        float[] mono = samples[0];

//////        //////        int samplesPerMs = sampleRate / 1000;

//////        //////        for (int i = 0; i < mono.Length; i += samplesPerMs)

//////        //////        {

//////        //////            float sum = 0;

//////        //////            int count = 0;

//////        //////            for (int j = i; j < i + samplesPerMs && j < mono.Length; j++)

//////        //////            {

//////        //////                sum += Math.Abs(mono[j]);

//////        //////                count++;

//////        //////            }

//////        //////            float avg = (count > 0) ? sum / count : 0;

//////        //////            writer.WriteLine($"{i / samplesPerMs},{avg}");

//////        //////        }

//////        //////    }

//////        //////}//public static void ExportPerMillisecond(string path, float[][] samples, int sampleRate)

 

//////        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Millisecond,Amplitude");

//////                float[] mono = samples; // samples[0];

//////                int samplesPerMs = sampleRate / 1000;

//////                for (int i = 0; i < mono.Length; i += samplesPerMs)

//////                {

//////                    float sum = 0;

//////                    int count = 0;

//////                    for (int j = i; j < i + samplesPerMs && j < mono.Length; j++)

//////                    {

//////                        sum += Math.Abs(mono[j]);

//////                        count++;

//////                    }

//////                    float avg = (count > 0) ? sum / count : 0;

//////                    writer.WriteLine($"{i / samplesPerMs},{avg}");

//////                }

//////            }

//////        }//public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

 

 

 

 

 

 

 

 

//////    }

 

//////    public static class DxfVisualizer

//////    {

//////        public static void DrawDxf(string path, List<CrestTroughSegment> segments, int sampleRate)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("0\nSECTION\n2\nENTITIES");

//////                foreach (var seg in segments)

//////                {

//////                    double x = seg.StartSample * (1.0 / sampleRate);

//////                    double y = seg.PeakAmplitude * 100;

//////                    sw.WriteLine("0\nTEXT");

//////                    sw.WriteLine($"8\nCRESTTROUGHS\n10\n{x}\n20\n{y}\n40\n1.0\n1\n{(seg.IsCrest ? "C" : "T")}");

//////                }

//////                sw.WriteLine("0\nENDSEC\n0\nEOF");

//////            }

//////        }

//////    }

 

 

 

 

 

 

 

 

 

 

 

//////       public class WaveProcessor

//////      {

//////        //////     //   public void Start(string wavPath,  ProgressBar progressBar, Action<List<CrestTroughSegment>> onComplete)

//////        //////public List<CrestTroughSegment> Start(string path, ref ProgressBar progressBar)

//////        //////        {

//////        //////            int sampleRate;

//////        //////            bool stereo;

//////        //////            //     float[][] wavSamples = WavLoader.LoadPcmWav(wavPath, out sampleRate, out stereo);

 

//////        //////            //float[][] wavSamples = WavLoader.LoadPcmWav(wavPath, out sampleRate, out stereo);

 

//////        //////            float[] monoSamples = SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform.WavLoader

//////        //////                .LoadMonoPcmWav(wavPath, out sampleRate);

//////        //////            //  .LoadPcmWav(wavPath, out sampleRate);

 

 

 

//////        //////            float[] mono = monoSamples;// wavSamples[0];

 

//////        //////            progressBar.Minimum = 0;

//////        //////            progressBar.Maximum = mono.Length;

//////        //////            progressBar.Value = 0;

 

//////        //////            List<CrestTroughSegment> segments = CrestTroughAnalyzer.Analyze(mono);

 

//////        //////            for (int i = 0; i < mono.Length; i += 1000)

//////        //////            {

//////        //////                progressBar.Value = Math.Min(i, mono.Length);

//////        //////                Application.DoEvents();

//////        //////            }

 

//////        //////            onComplete?.Invoke(segments);

//////        //////        }

 

//////        public List<CrestTroughSegment> Start(string wavPath, ref ProgressBar progressBar)

//////        {

//////            int sampleRate;

//////            float[] monoSamples = WavLoader.LoadMonoPcmWav(wavPath, out sampleRate);

 

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = monoSamples.Length;

//////            progressBar.Value = 0;

 

//////            List<CrestTroughSegment> segments = CrestTroughAnalyzer.Analyze(monoSamples);

 

//////            // Simulate progress for visual feedback

//////            for (int i = 0; i < monoSamples.Length; i += 1000)

//////            {

//////                progressBar.Value = Math.Min(i, monoSamples.Length - 1);

//////                Application.DoEvents();

//////            }

 

//////            progressBar.Value = monoSamples.Length;

 

//////            return segments;

//////        }// public List<CrestTroughSegment> Start(string wavPath, ref ProgressBar progressBar)

 

//////    }// public class WaveProcessor

 

 

 

 

 

 

 

 

 

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class CrestTroughSegment

//////    {

//////        public int StartSample;

//////        public int EndSample;

//////        public float PeakAmplitude;

//////        public bool IsCrest;

//////    }

 

//////    public static class WavLoader

//////    {

//////        public static float[] LoadMonoPcmWav(string path, out int sampleRate)

//////        {

//////            using (var reader = new BinaryReader(File.OpenRead(path)))

//////            {

//////                reader.BaseStream.Seek(24, SeekOrigin.Begin);

//////                sampleRate = reader.ReadInt32();

 

//////                reader.BaseStream.Seek(22, SeekOrigin.Begin);

//////                int channels = reader.ReadInt16();

//////                if (channels != 1)

//////                    throw new InvalidOperationException("Only mono WAV files are supported.");

 

//////                reader.BaseStream.Seek(44, SeekOrigin.Begin);

//////                List<float> samples = new List<float>();

//////                while (reader.BaseStream.Position < reader.BaseStream.Length)

//////                {

//////                    short sample = reader.ReadInt16();

//////                    samples.Add(sample / 32768f);

//////                }

//////                return samples.ToArray();

//////            }

//////        }

//////    }

 

//////    public static class CrestTroughAnalyzer

//////    {

//////        public static List<CrestTroughSegment> Analyze(float[] samples)

//////        {

//////            List<CrestTroughSegment> segments = new List<CrestTroughSegment>();

//////            for (int i = 1; i < samples.Length - 1; i++)

//////            {

//////                bool isCrest = samples[i] > samples[i - 1] && samples[i] > samples[i + 1];

//////                bool isTrough = samples[i] < samples[i - 1] && samples[i] < samples[i + 1];

//////                if (isCrest || isTrough)

//////                {

//////                    segments.Add(new CrestTroughSegment

//////                    {

//////                        StartSample = i,

//////                        EndSample = i,

//////                        PeakAmplitude = samples[i],

//////                        IsCrest = isCrest

//////                    });

//////                }

//////            }

//////            return segments;

//////        }

//////    }

 

//////    public static class CrestTroughFilter

//////    {

//////        public static bool IsSmoothCrest(float[] samples, int start, int end)

//////        {

//////            for (int i = start + 1; i < end - 1; i++)

//////            {

//////                float prev = samples[i - 1];

//////                float curr = samples[i];

//////                float next = samples[i + 1];

//////                if (curr < prev && curr < next) return false;

//////            }

//////            return true;

//////        }

 

//////        public static bool IsSmoothTrough(float[] samples, int start, int end)

//////        {

//////            for (int i = start + 1; i < end - 1; i++)

//////            {

//////                float prev = samples[i - 1];

//////                float curr = samples[i];

//////                float next = samples[i + 1];

//////                if (curr > prev && curr > next) return false;

//////            }

//////            return true;

//////        }

 

//////        public static List<CrestTroughSegment> FilterSmoothSegments(List<CrestTroughSegment> segments, float[] samples)

//////        {

//////            List<CrestTroughSegment> result = new List<CrestTroughSegment>();

//////            foreach (var seg in segments)

//////            {

//////                bool isSmooth = seg.IsCrest

//////                    ? IsSmoothCrest(samples, seg.StartSample, seg.EndSample)

//////                    : IsSmoothTrough(samples, seg.StartSample, seg.EndSample);

//////                if (isSmooth)

//////                    result.Add(seg);

//////            }

//////            return result;

//////        }

//////    }

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string path, List<CrestTroughSegment> segments)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Start,End,Amplitude,Type");

//////                foreach (var seg in segments)

//////                {

//////                    writer.WriteLine($"{seg.StartSample},{seg.EndSample},{seg.PeakAmplitude},{(seg.IsCrest ? "Crest" : "Trough")}");

//////                }

//////            }

//////        }

 

//////        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Millisecond,Amplitude");

//////                int samplesPerMs = sampleRate / 1000;

//////                for (int i = 0; i < samples.Length; i += samplesPerMs)

//////                {

//////                    float sum = 0;

//////                    int count = 0;

//////                    for (int j = i; j < i + samplesPerMs && j < samples.Length; j++)

//////                    {

//////                        sum += Math.Abs(samples[j]);

//////                        count++;

//////                    }

//////                    float avg = (count > 0) ? sum / count : 0;

//////                    writer.WriteLine($"{i / samplesPerMs},{avg}");

//////                }

//////            }

//////        }

 

//////        public static void ExportFilteredSegments(string path, List<CrestTroughSegment> segments)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Type,StartSample,EndSample,DurationSamples");

//////                foreach (var seg in segments)

//////                {

//////                    writer.WriteLine($"{(seg.IsCrest ? "Crest" : "Trough")},{seg.StartSample},{seg.EndSample},{seg.EndSample - seg.StartSample}");

//////                }

//////            }

//////        }

//////    }

 

//////    public static class DxfVisualizer

//////    {

//////        public static void DrawDxf(string path, List<CrestTroughSegment> segments, int sampleRate)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("0\nSECTION\n2\nENTITIES");

//////                foreach (var seg in segments)

//////                {

//////                    double x = seg.StartSample * (1.0 / sampleRate);

//////                    double y = seg.PeakAmplitude * 100;

//////                    sw.WriteLine("0\nTEXT");

//////                    sw.WriteLine($"8\nCRESTTROUGHS\n10\n{x}\n20\n{y}\n40\n1.0\n1\n{(seg.IsCrest ? "C" : "T")}");

//////                }

//////                sw.WriteLine("0\nENDSEC\n0\nEOF");

//////            }

//////        }

//////    }

 

//////    public static class WavFilterSaver

//////    {

//////        //////public static void SaveFilteredWav(string outputPath, float[] originalSamples, List<CrestTroughSegment> segments)

//////        //////{

//////        //////    float[] filtered = new float[originalSamples.Length];

//////        //////    foreach (var segment in segments)

//////        //////    {

//////        //////        for (int i = segment.StartSample; i <= segment.EndSample; i++)

//////        //////        {

//////        //////            if (i >= 0 && i < originalSamples.Length)

//////        //////                filtered[i] = originalSamples[i];

//////        //////        }

//////        //////    }

 

//////        //////    using (var writer = new BinaryWriter(File.Create(outputPath)))

//////        //////    {

//////        //////        int sampleRate = 8000;

//////        //////        int bitsPerSample = 16;

//////        //////        short numChannels = 1;

//////        //////        short blockAlign = (short)(numChannels * bitsPerSample / 8);

//////        //////        int byteRate = sampleRate * blockAlign;

//////        //////        int dataLength = filtered.Length * blockAlign;

 

//////        //////        writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));

//////        //////        writer.Write(36 + dataLength);

//////        //////        writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"));

//////        //////        writer.Write(System.Text.Encoding.ASCII.GetBytes("fmt "));

//////        //////        writer.Write(16);

//////        //////        writer.Write((short)1);

//////        //////        writer.Write(numChannels);

//////        //////        writer.Write(sampleRate);

//////        //////        writer.Write(byteRate);

//////        //////        writer.Write(blockAlign);

//////        //////        writer.Write((short)bitsPerSample);

//////        //////        writer.Write(System.Text.Encoding.ASCII.GetBytes("data"));

//////        //////        writer.Write(dataLength);

 

//////        //////        foreach (float s in filtered)

//////        //////            writer.Write((short)(Math.Max(-1f, Math.Min(1f, s)) * 32767));

//////        //////    }

//////        //////}

 

 

 

 

 

 

 

 

//////        public static void SaveFilteredWav(string outputPath, float[] samples, List<CrestTroughSegment> segments, int sampleRate)

//////        {

//////            using (BinaryWriter writer = new BinaryWriter(File.Create(outputPath)))

//////            {

//////                int byteRate = sampleRate * 2; // mono, 16-bit

//////                int dataSize = samples.Length * 2;

 

//////                // WAV header

//////                writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));

//////                writer.Write(36 + dataSize); // file size - 8

//////                writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt "));

//////                writer.Write(16); // PCM chunk size

//////                writer.Write((short)1); // audio format

//////                writer.Write((short)1); // mono

//////                writer.Write(sampleRate);

//////                writer.Write(byteRate);

//////                writer.Write((short)2); // block align

//////                writer.Write((short)16); // bits per sample

//////                writer.Write(System.Text.Encoding.ASCII.GetBytes("data"));

//////                writer.Write(dataSize);

 

//////                // Segment filtering: only include samples in the filtered crests/troughs

//////                HashSet<int> included = new HashSet<int>();

//////                foreach (var seg in segments)

//////                {

//////                    for (int i = seg.StartSample; i <= seg.EndSample && i < samples.Length; i++)

//////                        included.Add(i);

//////                }

 

//////                for (int i = 0; i < samples.Length; i++)

//////                {

//////                    short sample = (short)(included.Contains(i) ? samples[i] * 32767f : 0);

//////                    writer.Write(sample);

//////                }

//////            }

//////        }

 

 

 

 

//////    }

 

//////    public class WaveProcessor

//////    {

//////        public List<CrestTroughSegment> Start(string wavPath, ref ProgressBar progressBar)

//////        {

//////            int sampleRate;

//////            float[] monoSamples = WavLoader.LoadMonoPcmWav(wavPath, out sampleRate);

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = monoSamples.Length;

//////            progressBar.Value = 0;

 

//////            List<CrestTroughSegment> segments = CrestTroughAnalyzer.Analyze(monoSamples);

 

//////            for (int i = 0; i < monoSamples.Length; i += 1000)

//////            {

//////                progressBar.Value = Math.Min(i, monoSamples.Length - 1);

//////                Application.DoEvents();

//////            }

 

//////            progressBar.Value = monoSamples.Length;

//////            return segments;

//////        }

//////    }

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class CrestTroughSegment

//////    {

//////        public int StartSample;

//////        public int EndSample;

//////        public float PeakAmplitude;

//////        public bool IsCrest;

//////    }

 

//////    public static class WavLoader

//////    {

//////        public static float[] LoadMonoPcmWav(string path, out int sampleRate)

//////        {

//////            using (var reader = new BinaryReader(File.OpenRead(path)))

//////            {

//////                reader.BaseStream.Seek(24, SeekOrigin.Begin);

//////                sampleRate = reader.ReadInt32();

 

//////                reader.BaseStream.Seek(22, SeekOrigin.Begin);

//////                int channels = reader.ReadInt16();

//////                if (channels != 1)

//////                    throw new InvalidOperationException("Only mono WAV files are supported.");

 

//////                reader.BaseStream.Seek(44, SeekOrigin.Begin);

//////                List<float> samples = new List<float>();

//////                while (reader.BaseStream.Position < reader.BaseStream.Length)

//////                {

//////                    short sample = reader.ReadInt16();

//////                    samples.Add(sample / 32768f);

//////                }

//////                return samples.ToArray();

//////            }

//////        }

//////    }

 

//////    public static class CrestTroughAnalyzer

//////    {

//////        public static List<CrestTroughSegment> Analyze(float[] samples)

//////        {

//////            List<CrestTroughSegment> segments = new List<CrestTroughSegment>();

//////            for (int i = 1; i < samples.Length - 1; i++)

//////            {

//////                bool isCrest = samples[i] > samples[i - 1] && samples[i] > samples[i + 1];

//////                bool isTrough = samples[i] < samples[i - 1] && samples[i] < samples[i + 1];

//////                if (isCrest || isTrough)

//////                {

//////                    segments.Add(new CrestTroughSegment

//////                    {

//////                        StartSample = i,

//////                        EndSample = i,

//////                        PeakAmplitude = samples[i],

//////                        IsCrest = isCrest

//////                    });

//////                }

//////            }

//////            return segments;

//////        }

//////    }

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string path, List<CrestTroughSegment> segments)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Start,End,Amplitude,Type");

//////                foreach (var seg in segments)

//////                {

//////                    writer.WriteLine($"{seg.StartSample},{seg.EndSample},{seg.PeakAmplitude},{(seg.IsCrest ? "Crest" : "Trough")}");

//////                }

//////            }

//////        }

 

//////        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Millisecond,Amplitude");

//////                int samplesPerMs = sampleRate / 1000;

//////                for (int i = 0; i < samples.Length; i += samplesPerMs)

//////                {

//////                    float sum = 0;

//////                    int count = 0;

//////                    for (int j = i; j < i + samplesPerMs && j < samples.Length; j++)

//////                    {

//////                        sum += Math.Abs(samples[j]);

//////                        count++;

//////                    }

//////                    float avg = (count > 0) ? sum / count : 0;

//////                    writer.WriteLine($"{i / samplesPerMs},{avg}");

//////                }

//////            }

//////        }

 

//////        public static void ExportFrequencies(string path, List<WaveformFrequencyEstimator.FrequencyPoint> frequencies)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("StartMs,DurationMs,FrequencyHz,MidiNote");

//////                foreach (var f in frequencies)

//////                {

//////                    sw.WriteLine($"{f.StartMs},{f.DurationMs},{f.FrequencyHz:F2},{f.MidiNote}");

//////                }

//////            }

//////        }

 

//////        public static void ExportSimilarSegmentCount(string path, Dictionary<string, int> patternCounts)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("PatternHash,Count");

//////                foreach (var kvp in patternCounts)

//////                {

//////                    sw.WriteLine($"{kvp.Key},{kvp.Value}");

//////                }

//////            }

//////        }

//////    }

 

//////    public static class DxfVisualizer

//////    {

//////        public static void DrawDxf(string path, List<CrestTroughSegment> segments, int sampleRate)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("0\nSECTION\n2\nENTITIES");

//////                foreach (var seg in segments)

//////                {

//////                    double x = seg.StartSample * (1.0 / sampleRate);

//////                    double y = seg.PeakAmplitude * 100;

//////                    sw.WriteLine("0\nTEXT");

//////                    sw.WriteLine($"8\nCRESTTROUGHS\n10\n{x}\n20\n{y}\n40\n1.0\n1\n{(seg.IsCrest ? "C" : "T")}");

//////                }

//////                sw.WriteLine("0\nENDSEC\n0\nEOF");

//////            }

//////        }

//////    }

 

//////    public static class WaveformFrequencyEstimator

//////    {

//////        public class FrequencyPoint

//////        {

//////            public int StartMs;

//////            public int DurationMs;

//////            public float FrequencyHz;

//////            public int MidiNote;

//////        }

 

//////        public static List<FrequencyPoint> EstimateFrequencies(float[] samples, int sampleRate)

//////        {

//////            int samplesPerMs = sampleRate / 1000;

//////            List<FrequencyPoint> result = new List<FrequencyPoint>();

 

//////            for (int ms = 0; ms < samples.Length / samplesPerMs; ms++)

//////            {

//////                int start = ms * samplesPerMs;

//////                int end = Math.Min(start + samplesPerMs, samples.Length);

 

//////                int zeroCrossings = 0;

//////                for (int i = start + 1; i < end; i++)

//////                {

//////                    if ((samples[i - 1] >= 0 && samples[i] < 0) || (samples[i - 1] < 0 && samples[i] >= 0))

//////                        zeroCrossings++;

//////                }

 

//////                float frequency = zeroCrossings * (sampleRate / (2f * samplesPerMs));

//////                int midiNote = (int)(69 + 12 * Math.Log(frequency / 440.0, 2));

 

//////                if (frequency > 20 && frequency < 20000)

//////                {

//////                    result.Add(new FrequencyPoint

//////                    {

//////                        StartMs = ms,

//////                        DurationMs = 1,

//////                        FrequencyHz = frequency,

//////                        MidiNote = midiNote

//////                    });

//////                }

//////            }

 

//////            return result;

//////        }

//////    }

 

//////    public static class WaveformPatternComparer

//////    {

//////        public static Dictionary<string, int> CountSimilarSegments(List<CrestTroughSegment> segments, float[] samples)

//////        {

//////            Dictionary<string, int> patternCount = new Dictionary<string, int>();

//////            foreach (var seg in segments)

//////            {

//////                int length = seg.EndSample - seg.StartSample + 1;

//////                if (length <= 0 || seg.StartSample + length > samples.Length)

//////                    continue;

 

//////                string pattern = "";

//////                for (int i = 1; i < length; i++)

//////                {

//////                    float delta = samples[seg.StartSample + i] - samples[seg.StartSample + i - 1];

//////                    pattern += delta >= 0 ? "+" : "-";

//////                }

 

//////                if (!patternCount.ContainsKey(pattern))

//////                    patternCount[pattern] = 0;

 

//////                patternCount[pattern]++;

//////            }

//////            return patternCount;

//////        }

//////    }

 

//////    public class WaveProcessor

//////    {

//////        public List<CrestTroughSegment> Start(string wavPath, ref ProgressBar progressBar)

//////        {

//////            int sampleRate;

//////            float[] monoSamples = WavLoader.LoadMonoPcmWav(wavPath, out sampleRate);

 

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = monoSamples.Length;

//////            progressBar.Value = 0;

 

//////            List<CrestTroughSegment> segments = CrestTroughAnalyzer.Analyze(monoSamples);

 

//////            for (int i = 0; i < monoSamples.Length; i += 1000)

//////            {

//////                progressBar.Value = Math.Min(i, monoSamples.Length - 1);

//////                Application.DoEvents();

//////            }

//////            progressBar.Value = monoSamples.Length;

 

//////            return segments;

//////        }

//////    }

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

////////////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

////////////{

////////////    public class CrestTroughSegment

////////////    {

////////////        public int StartSample;

////////////        public int EndSample;

////////////        public float PeakAmplitude;

////////////        public bool IsCrest;

////////////    }

 

////////////    public class FrequencyInfo

////////////    {

////////////        public int StartMs;

////////////        public int DurationMs;

////////////        public float Frequency;

////////////        public int MidiNote;

////////////    }

 

////////////    public static class WavLoader

////////////    {

////////////        public static float[] LoadMonoPcmWav(string path, out int sampleRate)

////////////        {

////////////            using (var reader = new BinaryReader(File.OpenRead(path)))

////////////            {

////////////                reader.BaseStream.Seek(24, SeekOrigin.Begin);

////////////                sampleRate = reader.ReadInt32();

////////////                reader.BaseStream.Seek(22, SeekOrigin.Begin);

////////////                int channels = reader.ReadInt16();

////////////                if (channels != 1)

////////////                    throw new InvalidOperationException("Only mono WAV files are supported.");

////////////                reader.BaseStream.Seek(44, SeekOrigin.Begin);

////////////                List<float> samples = new List<float>();

////////////                while (reader.BaseStream.Position < reader.BaseStream.Length)

////////////                {

////////////                    short sample = reader.ReadInt16();

////////////                    samples.Add(sample / 32768f);

////////////                }

////////////                return samples.ToArray();

////////////            }

////////////        }

////////////    }

 

////////////    public static class CrestTroughAnalyzer

////////////    {

////////////        public static List<CrestTroughSegment> Analyze(float[] samples)

////////////        {

////////////            List<CrestTroughSegment> segments = new List<CrestTroughSegment>();

////////////            for (int i = 1; i < samples.Length - 1; i++)

////////////            {

////////////                bool isCrest = samples[i] > samples[i - 1] && samples[i] > samples[i + 1];

////////////                bool isTrough = samples[i] < samples[i - 1] && samples[i] < samples[i + 1];

////////////                if (isCrest || isTrough)

////////////                {

////////////                    segments.Add(new CrestTroughSegment

////////////                    {

////////////                        StartSample = i,

////////////                        EndSample = i,

////////////                        PeakAmplitude = samples[i],

////////////                        IsCrest = isCrest

////////////                    });

////////////                }

////////////            }

////////////            return segments;

////////////        }

////////////    }

 

////////////    public static class CrestTroughFilter

////////////    {

////////////        public static List<CrestTroughSegment> FilterSmoothSegments(List<CrestTroughSegment> segments, float[] samples)

////////////        {

////////////            List<CrestTroughSegment> filtered = new List<CrestTroughSegment>();

////////////            foreach (var seg in segments)

////////////            {

////////////                bool sharp = false;

////////////                for (int i = seg.StartSample - 2; i <= seg.EndSample + 2 && i + 2 < samples.Length && i > 1; i++)

////////////                {

////////////                    float a = samples[i - 1];

////////////                    float b = samples[i];

////////////                    float c = samples[i + 1];

////////////                    float angle = Math.Abs((float)(Math.Atan2(c - b, 1) - Math.Atan2(b - a, 1)));

////////////                    if (angle > Math.PI / 4)

////////////                    {

////////////                        sharp = true;

////////////                        break;

////////////                    }

////////////                }

////////////                if (!sharp)

////////////                    filtered.Add(seg);

////////////            }

////////////            return filtered;

////////////        }

////////////    }

 

////////////    public static class CsvExporter

////////////    {

////////////        public static void ExportSegments(string path, List<CrestTroughSegment> segments)

////////////        {

////////////            using (StreamWriter writer = new StreamWriter(path))

////////////            {

////////////                writer.WriteLine("Start,End,Amplitude,Type");

////////////                foreach (var seg in segments)

////////////                {

////////////                    writer.WriteLine($"{seg.StartSample},{seg.EndSample},{seg.PeakAmplitude},{(seg.IsCrest ? "Crest" : "Trough")}");

////////////                }

////////////            }

////////////        }

 

////////////        public static void ExportFilteredSegments(string path, List<CrestTroughSegment> segments)

////////////        {

////////////            ExportSegments(path, segments);

////////////        }

 

////////////        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

////////////        {

////////////            using (StreamWriter writer = new StreamWriter(path))

////////////            {

////////////                writer.WriteLine("Millisecond,Amplitude");

////////////                int samplesPerMs = sampleRate / 1000;

////////////                for (int i = 0; i < samples.Length; i += samplesPerMs)

////////////                {

////////////                    float sum = 0;

////////////                    int count = 0;

////////////                    for (int j = i; j < i + samplesPerMs && j < samples.Length; j++)

////////////                    {

////////////                        sum += Math.Abs(samples[j]);

////////////                        count++;

////////////                    }

////////////                    float avg = (count > 0) ? sum / count : 0;

////////////                    writer.WriteLine($"{i / samplesPerMs},{avg}");

////////////                }

////////////            }

////////////        }

 

////////////        public static void ExportFrequencies(string path, List<FrequencyInfo> freqs)

////////////        {

////////////            using (StreamWriter writer = new StreamWriter(path))

////////////            {

////////////                writer.WriteLine("StartMs,DurationMs,Frequency,MIDINote");

////////////                foreach (var f in freqs)

////////////                {

////////////                    writer.WriteLine($"{f.StartMs},{f.DurationMs},{f.Frequency},{f.MidiNote}");

////////////                }

////////////            }

////////////        }

////////////    }

 

////////////    public static class WavFilterSaver

////////////    {

////////////        public static void SaveFilteredWav(string outPath, float[] allSamples, List<CrestTroughSegment> segments, int sampleRate)

////////////        {

////////////            short[] output = new short[allSamples.Length];

////////////            foreach (var seg in segments)

////////////            {

////////////                for (int i = seg.StartSample; i <= seg.EndSample && i < allSamples.Length; i++)

////////////                {

////////////                    output[i] = (short)(Math.Max(-1f, Math.Min(1f, allSamples[i])) * 32767);

////////////                }

////////////            }

////////////            using (var writer = new BinaryWriter(File.Create(outPath)))

////////////            {

////////////                int byteRate = sampleRate * 2;

////////////                writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));

////////////                writer.Write(36 + output.Length * 2);

////////////                writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt "));

////////////                writer.Write(16);

////////////                writer.Write((short)1);

////////////                writer.Write((short)1);

////////////                writer.Write(sampleRate);

////////////                writer.Write(byteRate);

////////////                writer.Write((short)2);

////////////                writer.Write((short)16);

////////////                writer.Write(System.Text.Encoding.ASCII.GetBytes("data"));

////////////                writer.Write(output.Length * 2);

////////////                foreach (short s in output)

////////////                {

////////////                    writer.Write(s);

////////////                }

////////////            }

////////////        }

////////////    }

 

////////////    public class WaveProcessor

////////////    {

////////////        public List<CrestTroughSegment> Start(string wavPath, ref ProgressBar progressBar)

////////////        {

////////////            int sampleRate;

////////////            float[] monoSamples = WavLoader.LoadMonoPcmWav(wavPath, out sampleRate);

////////////            progressBar.Minimum = 0;

////////////            progressBar.Maximum = monoSamples.Length;

////////////            progressBar.Value = 0;

////////////            List<CrestTroughSegment> segments = CrestTroughAnalyzer.Analyze(monoSamples);

////////////            for (int i = 0; i < monoSamples.Length; i += 1000)

////////////            {

////////////                progressBar.Value = Math.Min(i, monoSamples.Length - 1);

////////////                Application.DoEvents();

////////////            }

////////////            progressBar.Value = monoSamples.Length;

////////////            return segments;

////////////        }

////////////    }

////////////} // end namespace

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//////namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

//////{

//////    public class CrestTroughSegment

//////    {

//////        public int StartSample;

//////        public int EndSample;

//////        public float PeakAmplitude;

//////        public bool IsCrest;

//////    }

 

//////    public class FrequencyInfo

//////    {

//////        public int StartMillisecond;

//////        public int DurationMs;

//////        public float FrequencyHz;

//////        public int MidiNoteNumber;

//////    }

 

//////    public static class WavLoader

//////    {

//////        public static float[] LoadMonoPcmWav(string path, out int sampleRate)

//////        {

//////            using (var reader = new BinaryReader(File.OpenRead(path)))

//////            {

//////                reader.BaseStream.Seek(24, SeekOrigin.Begin);

//////                sampleRate = reader.ReadInt32();

//////                reader.BaseStream.Seek(22, SeekOrigin.Begin);

//////                int channels = reader.ReadInt16();

//////                if (channels != 1)

//////                    throw new InvalidOperationException("Only mono WAV files are supported.");

//////                reader.BaseStream.Seek(44, SeekOrigin.Begin);

//////                List<float> samples = new List<float>();

//////                while (reader.BaseStream.Position < reader.BaseStream.Length)

//////                {

//////                    short sample = reader.ReadInt16();

//////                    samples.Add(sample / 32768f);

//////                }

//////                return samples.ToArray();

//////            }

//////        }

//////    }

 

//////    public static class CrestTroughAnalyzer

//////    {

//////        public static List<CrestTroughSegment> Analyze(float[] samples)

//////        {

//////            List<CrestTroughSegment> segments = new List<CrestTroughSegment>();

//////            for (int i = 1; i < samples.Length - 1; i++)

//////            {

//////                bool isCrest = samples[i] > samples[i - 1] && samples[i] > samples[i + 1];

//////                bool isTrough = samples[i] < samples[i - 1] && samples[i] < samples[i + 1];

//////                if (isCrest || isTrough)

//////                {

//////                    segments.Add(new CrestTroughSegment

//////                    {

//////                        StartSample = i,

//////                        EndSample = i,

//////                        PeakAmplitude = samples[i],

//////                        IsCrest = isCrest

//////                    });

//////                }

//////            }

//////            return segments;

//////        }

//////    }

 

//////    public static class CrestTroughFilter

//////    {

//////        public static List<CrestTroughSegment> FilterSmoothSegments(List<CrestTroughSegment> segments, float[] samples)

//////        {

//////            List<CrestTroughSegment> result = new List<CrestTroughSegment>();

//////            foreach (var seg in segments)

//////            {

//////                int idx = seg.StartSample;

//////                if (idx < 2 || idx > samples.Length - 3) continue;

//////                float prev = samples[idx - 1];

//////                float curr = samples[idx];

//////                float next = samples[idx + 1];

//////                float angle1 = Math.Abs(curr - prev);

//////                float angle2 = Math.Abs(curr - next);

//////                if (angle1 < 0.2f && angle2 < 0.2f)

//////                    result.Add(seg);

//////            }

//////            return result;

//////        }

//////    }

 

//////    public static class CsvExporter

//////    {

//////        public static void ExportSegments(string path, List<CrestTroughSegment> segments)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Start,End,Amplitude,Type");

//////                foreach (var seg in segments)

//////                {

//////                    writer.WriteLine($"{seg.StartSample},{seg.EndSample},{seg.PeakAmplitude},{(seg.IsCrest ? "Crest" : "Trough")}");

//////                }

//////            }

//////        }

 

//////        public static void ExportFilteredSegments(string path, List<CrestTroughSegment> segments)

//////        {

//////            ExportSegments(path, segments);

//////        }

 

//////        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Millisecond,Amplitude");

//////                int samplesPerMs = sampleRate / 1000;

//////                for (int i = 0; i < samples.Length; i += samplesPerMs)

//////                {

//////                    float sum = 0;

//////                    int count = 0;

//////                    for (int j = i; j < i + samplesPerMs && j < samples.Length; j++)

//////                    {

//////                        sum += Math.Abs(samples[j]);

//////                        count++;

//////                    }

//////                    float avg = (count > 0) ? sum / count : 0;

//////                    writer.WriteLine($"{i / samplesPerMs},{avg}");

//////                }

//////            }

//////        }

 

//////        public static void ExportSimilarSegmentCount(string path, Dictionary<string, int> patternCounts)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("Pattern,Count");

//////                foreach (var pair in patternCounts)

//////                    writer.WriteLine($"{pair.Key},{pair.Value}");

//////            }

//////        }

 

//////        public static void ExportFrequencies(string path, List<FrequencyInfo> freqList)

//////        {

//////            using (StreamWriter writer = new StreamWriter(path))

//////            {

//////                writer.WriteLine("StartMs,DurationMs,Freq,MidiNote");

//////                foreach (var f in freqList)

//////                    writer.WriteLine($"{f.StartMillisecond},{f.DurationMs},{f.FrequencyHz},{f.MidiNoteNumber}");

//////            }

//////        }

//////    }

 

//////    public static class DxfVisualizer

//////    {

//////        public static void DrawDxf(string path, List<CrestTroughSegment> segments, int sampleRate)

//////        {

//////            using (StreamWriter sw = new StreamWriter(path))

//////            {

//////                sw.WriteLine("0\nSECTION\n2\nENTITIES");

//////                foreach (var seg in segments)

//////                {

//////                    double x = seg.StartSample * (1.0 / sampleRate);

//////                    double y = seg.PeakAmplitude * 100;

//////                    sw.WriteLine("0\nTEXT");

//////                    sw.WriteLine($"8\nCRESTTROUGHS\n10\n{x}\n20\n{y}\n40\n1.0\n1\n{(seg.IsCrest ? "C" : "T")}");

//////                }

//////                sw.WriteLine("0\nENDSEC\n0\nEOF");

//////            }

//////        }

//////    }

 

//////    public static class WavFilterSaver

//////    {

//////        public static void SaveFilteredWav(string outputPath, float[] originalSamples, List<CrestTroughSegment> filteredSegments, int sampleRate)

//////        {

//////            short[] output = new short[originalSamples.Length];

//////            foreach (var seg in filteredSegments)

//////            {

//////                output[seg.StartSample] = (short)(originalSamples[seg.StartSample] * 32767);

//////            }

 

//////            using (var writer = new BinaryWriter(File.Create(outputPath)))

//////            {

//////                int byteRate = sampleRate * 2;

//////                writer.Write(new[] { 'R', 'I', 'F', 'F' });

//////                writer.Write(36 + output.Length * 2);

//////                writer.Write(new[] { 'W', 'A', 'V', 'E' });

//////                writer.Write(new[] { 'f', 'm', 't', ' ' });

//////                writer.Write(16);

//////                writer.Write((short)1);

//////                writer.Write((short)1);

//////                writer.Write(sampleRate);

//////                writer.Write(byteRate);

//////                writer.Write((short)2);

//////                writer.Write((short)16);

//////                writer.Write(new[] { 'd', 'a', 't', 'a' });

//////                writer.Write(output.Length * 2);

//////                foreach (short sample in output)

//////                    writer.Write(sample);

//////            }

//////        }

//////    }

 

//////    public class WaveProcessor

//////    {

//////        public List<CrestTroughSegment> Start(string wavPath, ref ProgressBar progressBar)

//////        {

//////            int sampleRate;

//////            float[] monoSamples = WavLoader.LoadMonoPcmWav(wavPath, out sampleRate);

//////            progressBar.Minimum = 0;

//////            progressBar.Maximum = monoSamples.Length;

//////            progressBar.Value = 0;

//////            List<CrestTroughSegment> segments = CrestTroughAnalyzer.Analyze(monoSamples);

//////            for (int i = 0; i < monoSamples.Length; i += 1000)

//////            {

//////                progressBar.Value = Math.Min(i, monoSamples.Length - 1);

//////                Application.DoEvents();

//////            }

//////            progressBar.Value = monoSamples.Length;

//////            return segments;

//////        }

//////    }

 

//////    public static class WaveformFrequencyEstimator

//////    {

//////        public class FrequencyPoint

//////        {

//////            public int StartMs;

//////            public int DurationMs;

//////            public float Frequency;

//////        }

 

//////        public static List<FrequencyPoint> EstimateFrequencies(float[] samples, int sampleRate)

//////        {

//////            List<FrequencyPoint> list = new List<FrequencyPoint>();

//////            int samplesPerMs = sampleRate / 1000;

//////            for (int i = 0; i + samplesPerMs < samples.Length; i += samplesPerMs)

//////            {

//////                float sum = 0;

//////                for (int j = 0; j < samplesPerMs; j++)

//////                {

//////                    sum += Math.Abs(samples[i + j]);

//////                }

//////                float freq = sum * 20; // Dummy linear frequency proxy

//////                list.Add(new FrequencyPoint { StartMs = i / samplesPerMs, DurationMs = 1, Frequency = freq });

//////            }

//////            return list;

//////        }

//////    }

 

//////    public static class WaveformPatternComparer

//////    {

//////        public static Dictionary<string, int> ComparePatterns(List<WaveformFrequencyEstimator.FrequencyPoint> freqPoints)

//////        {

//////            var result = new Dictionary<string, int>();

//////            foreach (var point in freqPoints)

//////            {

//////                string key = ((int)(point.Frequency / 10)).ToString();

//////                if (!result.ContainsKey(key))

//////                    result[key] = 0;

//////                result[key]++;

//////            }

//////            return result;

//////        }

//////    }

//////}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

{

    public class FrequencyInfo

    {

        public int StartMillis;

        public int DurationMillis;

        public float Frequency;

        public int MidiNote;

    }

 

    public static class WaveformFrequencyEstimator

    {

        public class FrequencyPoint

        {

            public int StartMillis;

            public int DurationMillis;

            public float Frequency;

        }

 

        public static List<FrequencyPoint> EstimateFrequencies(List<CrestTroughSegment> segments, int sampleRate)

        {

            var results = new List<FrequencyPoint>();

            foreach (var seg in segments)

            {

                int startMs = (int)(seg.StartSample * 1000.0 / sampleRate);

                int endMs = (int)(seg.EndSample * 1000.0 / sampleRate);

                int duration = Math.Max(1, endMs - startMs);

 

                float freq = 0;

                if (duration > 0)

                {

                    float samples = seg.EndSample - seg.StartSample;

                    freq = 1000.0f / duration * (samples / 2); // approx half-wave count

                }

 

                results.Add(new FrequencyPoint { StartMillis = startMs, DurationMillis = duration, Frequency = freq });

            }

            return results;

        }

    }

 

    public static class WaveformPatternComparer

    {

        public static int CountSimilarSegments(List<CrestTroughSegment> segments, List<WaveformFrequencyEstimator.FrequencyPoint> frequencies)

        {

            int similarCount = 0;

            for (int i = 1; i < segments.Count; i++)

            {

                float angleDelta = Math.Abs(segments[i].AverageAngle - segments[i - 1].AverageAngle);

                float freqDelta = Math.Abs(frequencies[i].Frequency - frequencies[i - 1].Frequency);

                if (angleDelta < 10 && freqDelta < 3)

                   similarCount++;

            }

            return similarCount;

        }

    }

 

    public static class CsvExporter

    {

        public static void ExportSegments(string path, List<CrestTroughSegment> segments)

        {

            using (var sw = new StreamWriter(path))

            {

                sw.WriteLine("Index,StartSample,EndSample,StartValue,EndValue,Type,AverageAngle");

                for (int i = 0; i < segments.Count; i++)

                {

                    var seg = segments[i];

                    sw.WriteLine($"{i},{seg.StartSample},{seg.EndSample},{seg.StartValue},{seg.EndValue},{seg.Type},{seg.AverageAngle}");

                }

            }

        }

 

        public static void ExportFilteredSegments(string path, List<CrestTroughSegment> segments)

        {

            ExportSegments(path, segments);

        }

 

        public static void ExportPerMillisecond(string path, float[] samples, int sampleRate)

        {

            using (var sw = new StreamWriter(path))

            {

                sw.WriteLine("Millis,AvgAmplitude");

                int samplesPerMs = sampleRate / 1000;

                for (int ms = 0; ms < samples.Length / samplesPerMs; ms++)

                {

                    float sum = 0;

                    for (int j = 0; j < samplesPerMs; j++)

                    {

                        int idx = ms * samplesPerMs + j;

                        if (idx >= samples.Length) break;

                        sum += Math.Abs(samples[idx]);

                    }

                    sw.WriteLine($"{ms},{sum / samplesPerMs}");

                }

            }

        }

 

        public static void ExportFrequencyInfo(string path, List<WaveformFrequencyEstimator.FrequencyPoint> freqs)

        {

            using (var sw = new StreamWriter(path))

            {

                sw.WriteLine("StartMillis,DurationMillis,Frequency,MidiNote");

                foreach (var f in freqs)

                {

                    int midi = FrequencyToMidi(f.Frequency);

                    sw.WriteLine($"{f.StartMillis},{f.DurationMillis},{f.Frequency},{midi}");

                }

            }

        }

 

        private static int FrequencyToMidi(float freq)

        {

            if (freq <= 0) return -1;

            return (int)Math.Round(69 + 12 * Math.Log(freq / 440.0, 2));

        }

 

        public static void ExportSimilarSegmentCount(string path, int count)

        {

            File.WriteAllText(path, $"Similar segment count = {count}");

        }

    }

 

    public class CrestTroughSegment

    {

        public int StartSample;

        public int EndSample;

        public float StartValue;

        public float EndValue;

        public string Type;

        public float AverageAngle;

    }

}//namespace SAANS_WAVEFILES_CREST_TROUGHS_ANALYSISWaveform

No comments:

Post a Comment