Example #1
0
        public static void Execute(Arguments arguments)
        {
            const string Title = "# DETERMINING SIGNAL TO NOISE RATIO IN RECORDING";
            string       date  = "# DATE AND TIME: " + DateTime.Now;

            Log.WriteLine(Title);
            Log.WriteLine(date);
            Log.Verbosity = 1;

            var input                    = arguments.Source;
            var sourceFileName           = input.Name;
            var outputDir                = arguments.Output;
            var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(input.FullName);
            var outputTxtPath            = Path.Combine(outputDir.FullName, fileNameWithoutExtension + ".txt").ToFileInfo();

            Log.WriteIfVerbose("# Recording file: " + input.FullName);
            Log.WriteIfVerbose("# Config file:    " + arguments.Config);
            Log.WriteIfVerbose("# Output folder =" + outputDir.FullName);
            FileTools.WriteTextFile(outputTxtPath.FullName, date + "\n# Recording file: " + input.FullName);

            //READ PARAMETER VALUES FROM INI FILE
            // load YAML configuration
            Config configuration = ConfigFile.Deserialize(arguments.Config);

            //ii: SET SONOGRAM CONFIGURATION
            SonogramConfig sonoConfig = new SonogramConfig(); //default values config

            sonoConfig.SourceFName        = input.FullName;
            sonoConfig.WindowSize         = configuration.GetIntOrNull(AnalysisKeys.KeyFrameSize) ?? 512;
            sonoConfig.WindowOverlap      = configuration.GetDoubleOrNull(AnalysisKeys.FrameOverlap) ?? 0.5;
            sonoConfig.WindowFunction     = configuration[AnalysisKeys.KeyWindowFunction];
            sonoConfig.NPointSmoothFFT    = configuration.GetIntOrNull(AnalysisKeys.KeyNPointSmoothFft) ?? 256;
            sonoConfig.NoiseReductionType = SNR.KeyToNoiseReductionType(configuration[AnalysisKeys.NoiseReductionType]);

            int    minHz          = configuration.GetIntOrNull("MIN_HZ") ?? 0;
            int    maxHz          = configuration.GetIntOrNull("MAX_HZ") ?? 11050;
            double segK1          = configuration.GetDoubleOrNull("SEGMENTATION_THRESHOLD_K1") ?? 0;
            double segK2          = configuration.GetDoubleOrNull("SEGMENTATION_THRESHOLD_K2") ?? 0;
            double latency        = configuration.GetDoubleOrNull("K1_K2_LATENCY") ?? 0;
            double vocalGap       = configuration.GetDoubleOrNull("VOCAL_GAP") ?? 0;
            double minVocalLength = configuration.GetDoubleOrNull("MIN_VOCAL_DURATION") ?? 0;

            //bool DRAW_SONOGRAMS = (bool?)configuration.DrawSonograms ?? true;    //options to draw sonogram

            //double intensityThreshold = Acoustics.AED.Default.intensityThreshold;
            //if (dict.ContainsKey(key_AED_INTENSITY_THRESHOLD)) intensityThreshold = Double.Parse(dict[key_AED_INTENSITY_THRESHOLD]);
            //int smallAreaThreshold = Acoustics.AED.Default.smallAreaThreshold;
            //if( dict.ContainsKey(key_AED_SMALL_AREA_THRESHOLD))   smallAreaThreshold = Int32.Parse(dict[key_AED_SMALL_AREA_THRESHOLD]);

            // COnvert input recording into wav
            var convertParameters = new AudioUtilityRequest {
                TargetSampleRate = 17640
            };
            var fileToAnalyse = new FileInfo(Path.Combine(outputDir.FullName, "temp.wav"));

            if (File.Exists(fileToAnalyse.FullName))
            {
                File.Delete(fileToAnalyse.FullName);
            }

            var convertedFileInfo = AudioFilePreparer.PrepareFile(
                input,
                fileToAnalyse,
                convertParameters,
                outputDir);

            // (A) ##########################################################################################################################
            AudioRecording recording              = new AudioRecording(fileToAnalyse.FullName);
            int            signalLength           = recording.WavReader.Samples.Length;
            TimeSpan       wavDuration            = TimeSpan.FromSeconds(recording.WavReader.Time.TotalSeconds);
            double         frameDurationInSeconds = sonoConfig.WindowSize / (double)recording.SampleRate;
            TimeSpan       frameDuration          = TimeSpan.FromTicks((long)(frameDurationInSeconds * TimeSpan.TicksPerSecond));
            int            stepSize = (int)Math.Floor(sonoConfig.WindowSize * (1 - sonoConfig.WindowOverlap));
            double         stepDurationInSeconds = sonoConfig.WindowSize * (1 - sonoConfig.WindowOverlap)
                                                   / recording.SampleRate;
            TimeSpan stepDuration    = TimeSpan.FromTicks((long)(stepDurationInSeconds * TimeSpan.TicksPerSecond));
            double   framesPerSecond = 1 / stepDuration.TotalSeconds;
            int      frameCount      = signalLength / stepSize;

            // (B) ################################## EXTRACT ENVELOPE and SPECTROGRAM ##################################
            var dspOutput = DSP_Frames.ExtractEnvelopeAndFfts(
                recording,
                sonoConfig.WindowSize,
                sonoConfig.WindowOverlap);

            //double[] avAbsolute = dspOutput.Average; //average absolute value over the minute recording

            // (C) ################################## GET SIGNAL WAVEFORM ##################################
            double[] signalEnvelope   = dspOutput.Envelope;
            double   avSignalEnvelope = signalEnvelope.Average();

            // (D) ################################## GET Amplitude Spectrogram ##################################
            double[,] amplitudeSpectrogram = dspOutput.AmplitudeSpectrogram; // get amplitude spectrogram.

            // (E) ################################## Generate deciBel spectrogram from amplitude spectrogram
            double epsilon = Math.Pow(0.5, recording.BitsPerSample - 1);

            double[,] deciBelSpectrogram = MFCCStuff.DecibelSpectra(
                dspOutput.AmplitudeSpectrogram,
                dspOutput.WindowPower,
                recording.SampleRate,
                epsilon);

            LoggedConsole.WriteLine("# Finished calculating decibel spectrogram.");

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("\nSIGNAL PARAMETERS");
            sb.AppendLine("Signal Duration     =" + wavDuration);
            sb.AppendLine("Sample Rate         =" + recording.SampleRate);
            sb.AppendLine("Min Signal Value    =" + dspOutput.MinSignalValue);
            sb.AppendLine("Max Signal Value    =" + dspOutput.MaxSignalValue);
            sb.AppendLine("Max Absolute Ampl   =" + signalEnvelope.Max().ToString("F3") + "  (See Note 1)");
            sb.AppendLine("Epsilon Ampl (1 bit)=" + epsilon);

            sb.AppendLine("\nFRAME PARAMETERS");
            sb.AppendLine("Window Size    =" + sonoConfig.WindowSize);
            sb.AppendLine("Frame Count    =" + frameCount);
            sb.AppendLine("Envelope length=" + signalEnvelope.Length);
            sb.AppendLine("Frame Duration =" + frameDuration.TotalMilliseconds.ToString("F3") + " ms");
            sb.AppendLine("Frame overlap  =" + sonoConfig.WindowOverlap);
            sb.AppendLine("Step Size      =" + stepSize);
            sb.AppendLine("Step duration  =" + stepDuration.TotalMilliseconds.ToString("F3") + " ms");
            sb.AppendLine("Frames Per Sec =" + framesPerSecond.ToString("F1"));

            sb.AppendLine("\nFREQUENCY PARAMETERS");
            sb.AppendLine("Nyquist Freq    =" + dspOutput.NyquistFreq + " Hz");
            sb.AppendLine("Freq Bin Width  =" + dspOutput.FreqBinWidth.ToString("F2") + " Hz");
            sb.AppendLine("Nyquist Bin     =" + dspOutput.NyquistBin);

            sb.AppendLine("\nENERGY PARAMETERS");
            double val = dspOutput.FrameEnergy.Min();

            sb.AppendLine(
                "Minimum dB / frame       =" + (10 * Math.Log10(val)).ToString("F2") + "  (See Notes 2, 3 & 4)");
            val = dspOutput.FrameEnergy.Max();
            sb.AppendLine("Maximum dB / frame       =" + (10 * Math.Log10(val)).ToString("F2"));

            sb.AppendLine("\ndB NOISE SUBTRACTION");
            double noiseRange = 2.0;

            //sb.AppendLine("Noise (estimate of mode) =" + sonogram.SnrData.NoiseSubtracted.ToString("F3") + " dB   (See Note 5)");
            //double noiseSpan = sonogram.SnrData.NoiseRange;
            //sb.AppendLine("Noise range              =" + noiseSpan.ToString("F2") + " to +" + (noiseSpan * -1).ToString("F2") + " dB   (See Note 6)");
            //sb.AppendLine("SNR (max frame-noise)    =" + sonogram.SnrData.Snr.ToString("F2") + " dB   (See Note 7)");

            //sb.Append("\nSEGMENTATION PARAMETERS");
            //sb.Append("Segment Thresholds K1: {0:f2}.  K2: {1:f2}  (See Note 8)", segK1, segK2);
            //sb.Append("# Event Count = " + predictedEvents.Count());

            FileTools.Append2TextFile(outputTxtPath.FullName, sb.ToString());
            FileTools.Append2TextFile(outputTxtPath.FullName, GetSNRNotes(noiseRange).ToString());

            // (F) ################################## DRAW IMAGE 1: original spectorgram
            Log.WriteLine("# Start drawing noise reduced sonograms.");
            TimeSpan X_AxisInterval = TimeSpan.FromSeconds(1);

            //int Y_AxisInterval = (int)Math.Round(1000 / dspOutput.FreqBinWidth);
            int nyquist    = recording.SampleRate / 2;
            int hzInterval = 1000;

            var image1 = DrawSonogram(deciBelSpectrogram, wavDuration, X_AxisInterval, stepDuration, nyquist, hzInterval);

            // (G) ################################## Calculate modal background noise spectrum in decibels
            //double SD_COUNT = -0.5; // number of SDs above the mean for noise removal
            //NoiseReductionType nrt = NoiseReductionType.MODAL;
            //System.Tuple<double[,], double[]> tuple = SNR.NoiseReduce(deciBelSpectrogram, nrt, SD_COUNT);

            //double upperPercentileBound = 0.2;    // lowest percentile for noise removal
            //NoiseReductionType nrt = NoiseReductionType.LOWEST_PERCENTILE;
            //System.Tuple<double[,], double[]> tuple = SNR.NoiseReduce(deciBelSpectrogram, nrt, upperPercentileBound);

            // (H) ################################## Calculate BRIGGS noise removal from amplitude spectrum
            int percentileBound = 20; // low energy percentile for noise removal

            //double binaryThreshold   = 0.6;   //works for higher SNR recordings
            double binaryThreshold = 0.4; //works for lower SNR recordings

            //double binaryThreshold = 0.3;   //works for lower SNR recordings
            double[,] m = NoiseRemoval_Briggs.BriggsNoiseFilterAndGetMask(
                amplitudeSpectrogram,
                percentileBound,
                binaryThreshold);

            string title  = "TITLE";
            var    image2 = NoiseRemoval_Briggs.DrawSonogram(
                m,
                wavDuration,
                X_AxisInterval,
                stepDuration,
                nyquist, hzInterval,
                title);

            //Image image2 = NoiseRemoval_Briggs.BriggsNoiseFilterAndGetSonograms(amplitudeSpectrogram, upperPercentileBound, binaryThreshold,
            //                                                                          wavDuration, X_AxisInterval, stepDuration, Y_AxisInterval);

            // (I) ################################## Calculate MEDIAN noise removal from amplitude spectrum

            //double upperPercentileBound = 0.8;    // lowest percentile for noise removal
            //NoiseReductionType nrt = NoiseReductionType.MEDIAN;
            //System.Tuple<double[,], double[]> tuple = SNR.NoiseReduce(deciBelSpectrogram, nrt, upperPercentileBound);

            //double[,] noiseReducedSpectrogram1 = tuple.Item1;  //
            //double[] noiseProfile              = tuple.Item2;  // smoothed modal profile

            //SNR.NoiseProfile dBProfile = SNR.CalculateNoiseProfile(deciBelSpectrogram, SD_COUNT);       // calculate noise value for each freq bin.
            //double[] noiseProfile = DataTools.filterMovingAverage(dBProfile.noiseThresholds, 7);        // smooth modal profile
            //double[,] noiseReducedSpectrogram1 = SNR.TruncateBgNoiseFromSpectrogram(deciBelSpectrogram, dBProfile.noiseThresholds);
            //Image image2 = DrawSonogram(noiseReducedSpectrogram1, wavDuration, X_AxisInterval, stepDuration, Y_AxisInterval);

            var combinedImage = ImageTools.CombineImagesVertically(image1, image2);

            string imagePath = Path.Combine(outputDir.FullName, fileNameWithoutExtension + ".png");

            combinedImage.Save(imagePath);

            // (G) ################################## Calculate modal background noise spectrum in decibels

            Log.WriteLine("# Finished recording:- " + input.Name);
        }
        public static void ReadSpectralIndicesAndWriteToDataTable(string[] spectrogramKeys, DateTime thisDate, DirectoryInfo targetDirInfo, string targetFileName, string opFilePath)
        {
            TimeSpan roundingInterval = TimeSpan.FromMinutes(1);

            // thisDate.Round(roundingInterval); // could not get this to work
            int year            = thisDate.Year;
            int thisDayOfYear   = thisDate.DayOfYear;
            int thisStartMinute = (thisDate.Hour * 60) + thisDate.Minute;

            if (thisDate.Second > 30)
            {
                thisStartMinute++;
            }

            // reads all known files spectral indices
            Dictionary <string, double[, ]> dict = IndexMatrices.ReadSpectrogramCsvFiles(targetDirInfo, targetFileName, spectrogramKeys, out var freqBinCount);

            if (dict.Count() == 0)
            {
                LoggedConsole.WriteLine("No spectrogram matrices in the dictionary. Spectrogram files do not exist?");
                return;
            }

            // set up the output file with headers if it does not exist
            if (!File.Exists(opFilePath))
            {
                string outputCsvHeader = "Year,DayOfYear,MinOfDay,FreqBin";
                foreach (string key in dict.Keys)
                {
                    outputCsvHeader = outputCsvHeader + "," + key;
                }

                FileTools.WriteTextFile(opFilePath, outputCsvHeader);
            }

            List <string> lines     = new List <string>();
            string        linestart = $"{year},{thisDayOfYear}";

            //int minutesInThisMatrix = 2;
            // number of minutes = number of columns in matrix
            int minutesInThisMatrix = dict[spectrogramKeys[1]].GetLength(1);

            freqBinCount = dict[spectrogramKeys[1]].GetLength(0);

            for (int min = 0; min < minutesInThisMatrix; min++)
            {
                int numberOfMinutes = thisStartMinute + min;
                for (int bin = 0; bin < freqBinCount; bin++)
                {
                    int           binId = freqBinCount - bin - 1;
                    StringBuilder line  = new StringBuilder(linestart + "," + numberOfMinutes + "," + binId);

                    foreach (string key in dict.Keys)
                    {
                        double[,] matrix = dict[key];

                        // do not need more than 6 decimal places for values which will ultimately transformed to colour bytes.
                        // cuts file size from 12.2 MB to 7.4 MB
                        string str = $",{matrix[bin, min]:F6}";
                        line.Append(str);
                    }

                    lines.Add(line.ToString());
                }
            }

            FileTools.Append2TextFile(opFilePath, lines);
        }
Example #3
0
        /// <summary>
        /// Wraps up the resources into a template.ZIP file
        /// and then runs a test on the source recording.
        /// </summary>
        public static void Execute(Arguments arguments)
        {
            if (arguments == null)
            {
                arguments = Dev();
            }

            string title = "# EDIT TEMPLATE.";
            string date  = "# DATE AND TIME: " + DateTime.Now;

            Log.WriteLine(title);
            Log.WriteLine(date);

            //ZIP THE OUTPUT FILES
            const bool ZipOutput = true;

            FileInfo iniPath = arguments.Config;

            string[] nameComponents = (Path.GetFileNameWithoutExtension(iniPath.Name)).Split('_');
            string   targetName     = nameComponents[0] + "_" + nameComponents[1];

            //i: Set up the file names
            DirectoryInfo outputDir       = iniPath.Directory;
            FileInfo      targetImagePath = outputDir.CombineFile(targetName + "_target.png"); // input image file
            FileInfo      binaryOpPath    = outputDir.CombineFile(targetName + "_binary.bmp");
            FileInfo      trinaryOpPath   = outputDir.CombineFile(targetName + "_trinary.bmp");
            FileInfo      sprOpPath       = outputDir.CombineFile(targetName + "_spr.txt");    // syntactic pattern recognition file
            //additional files to be zipped up with template
            FileInfo targetPath        = outputDir.CombineFile(targetName + "_target.txt");
            FileInfo targetNoNoisePath = outputDir.CombineFile(targetName + "_targetNoNoise.txt");
            FileInfo noisePath         = outputDir.CombineFile(targetName + "_noise.txt");

            //ii: READ PARAMETER VALUES FROM INI FILE
            var config = new ConfigDictionary(iniPath);
            Dictionary <string, string> dict = config.GetTable();
            string sourceFile           = dict[FeltTemplate_Create.key_SOURCE_RECORDING];
            string sourceDir            = dict[FeltTemplate_Create.key_SOURCE_DIRECTORY];
            double dB_Threshold         = double.Parse(dict[FeltTemplate_Create.key_DECIBEL_THRESHOLD]);
            double maxTemplateIntensity = double.Parse(dict[FeltTemplate_Create.key_TEMPLATE_MAX_INTENSITY]);
            int    neighbourhood        = int.Parse(dict[FeltTemplate_Create.key_DONT_CARE_NH]);   //the do not care neighbourhood
            int    lineLength           = int.Parse(dict[FeltTemplate_Create.key_LINE_LENGTH]);
            double templateThreshold    = dB_Threshold / maxTemplateIntensity;
            int    bitmapThreshold      = (int)(255 - (templateThreshold * 255));

            Log.WriteLine("#################################### WRITE THE BINARY TEMPLATE ##################################");
            Bitmap bitmap    = ImageTools.ReadImage2Bitmap(targetImagePath.FullName);
            var    binaryBmp = Image2BinaryBitmap(bitmap, bitmapThreshold);

            binaryBmp.Save(binaryOpPath.FullName);

            Log.WriteLine("#################################### WRITE THE TRINARY TEMPLATE ##################################");
            var trinaryBmp = Image2TrinaryBitmap(binaryBmp, neighbourhood);

            trinaryBmp.Save(trinaryOpPath.FullName);

            Log.WriteLine("#################################### WRITE THE SPR TEMPLATE ##################################");
            double[,] matrix = ImageTools.GreyScaleImage2Matrix(bitmap);
            matrix           = DataTools.MatrixRotate90Clockwise(matrix); //rows=time  cols=freq.
            //ImageTools.DrawMatrix(matrix, @"C:\SensorNetworks\Output\FELT_LewinsRail1\SPR_output1.bmp");
            //int smallLengthThreshold = 10;
            //var tuple = SPT.doSPT(matrix, templateThreshold, smallLengthThreshold);
            //matrix = tuple.Item1;
            //ImageTools.DrawMatrix(matrix, @"C:\SensorNetworks\Output\FELT_LewinsRail1\SPR_output2.bmp");
            char[,] spr = SprTools.Target2SymbolicTracks(matrix, templateThreshold, lineLength);
            FileTools.WriteMatrix2File(spr, sprOpPath.FullName);
            var    tuple1   = FindMatchingEvents.Execute_One_Spr_Match(spr, matrix, templateThreshold);
            double sprScore = tuple1.Item1;
            double dBScore  = sprScore * maxTemplateIntensity;

            Log.WriteLine("#################################### WRITE THE OSCILATION TEMPLATE ##################################");
            double[,] target = FileTools.ReadDoubles2Matrix(targetPath.FullName);
            // oscillations in time
            double[,] rotatedtarget = DataTools.MatrixRotate90Clockwise(target);
            var colSums = DataTools.GetColumnsAverages(rotatedtarget);

            double[] periods = Oscillations2010.PeriodicityAnalysis(colSums); // frame periodicity
            LoggedConsole.WriteLine("Periodicity (sec) = {0:f3},  {1:f3},  {2:f3}",
                                    periods[0] * FeltTemplates_Use.FeltFrameOffset, periods[1] * FeltTemplates_Use.FeltFrameOffset, periods[2] * FeltTemplates_Use.FeltFrameOffset);
            //double oscilFreq = indexOfMaxValue / dctDuration * 0.5; //Times 0.5 because index = Pi and not 2Pi

            // oscillations in freq i.e. harmonics
            colSums = DataTools.GetColumnsAverages(target);
            periods = Oscillations2010.PeriodicityAnalysis(colSums);
            LoggedConsole.WriteLine("Periodicity (Hz) = {0:f0},  {1:f0},  {2:f0}.",
                                    periods[0] * FeltTemplates_Use.FeltFreqBinWidth, periods[1] * FeltTemplates_Use.FeltFreqBinWidth, periods[2] * FeltTemplates_Use.FeltFreqBinWidth);
            //double oscilFreq = indexOfMaxValue / dctDuration * 0.5; //Times 0.5 because index = Pi and not 2Pi

            //FileTools.WriteMatrix2File(spr, sprOpPath);

            // ZIP THE OUTPUT
            Log.WriteLine("#################################### ZIP THE TEMPLATES ##################################");
            if (ZipOutput == true)
            {
                var filenames = new[]
                { iniPath, targetImagePath, binaryOpPath, targetPath, targetNoNoisePath, noisePath };
                string biOutZipFile = outputDir + targetName + "_binaryTemplate.zip";
                //FileTools.ZipFiles(filenames, biOutZipFile);

                filenames = new[]
                { iniPath, targetImagePath, trinaryOpPath, targetPath, targetNoNoisePath, noisePath };

                string triOutZipFile = outputDir + targetName + "_trinaryTemplate.zip";
                //FileTools.ZipFiles(filenames, triOutZipFile);

                filenames = new[]
                { iniPath, targetImagePath, sprOpPath, targetPath, targetNoNoisePath, noisePath };

                string sprOutZipFile = outputDir + targetName + "_syntacticTemplate.zip";
                //FileTools.ZipFiles(filenames, sprOutZipFile);

                // Zipping files can be done by using standard .NET 4.6 System.IO.Compression
                // however, this code hasn't been used in years and I've opted to just comment out the lines above
                throw new NotImplementedException("Zipping template files intentionally broken");
            }

            Log.WriteLine("\n\n#################################### TEST THE EXTRACTED EVENT ON SOURCE FILE ##################################");
            //vi: TEST THE EVENT ON ANOTHER FILE
            //felt  "C:\SensorNetworks\WavFiles\Canetoad\DM420010_128m_00s__130m_00s - Toads.mp3" C:\SensorNetworks\Output\FELT_CaneToad\FELT_CaneToad_Params.txt events.txt
            //string testRecording = @"C:\SensorNetworks\WavFiles\Gecko\Suburban_March2010\geckos_suburban_104.mp3";
            //string testRecording = @"C:\SensorNetworks\WavFiles\Gecko\Suburban_March2010\geckos_suburban_18.mp3";
            //string testRecording = @"C:\SensorNetworks\WavFiles\Currawongs\Currawong_JasonTagged\West_Knoll_Bees_20091102-170000.mp3";
            //string testRecording = @"C:\SensorNetworks\WavFiles\Curlew\Curlew2\Top_Knoll_-_St_Bees_20090517-210000.wav";

            string listOpDir        = "C:\\SensorNetworks\\Output\\FELT_templateList\\";
            string templateListPath = listOpDir + "templateTestList.txt";
            var    list             = new List <string>();

            list.Add("#" + outputDir + targetName + "_binaryTemplate.zip");
            list.Add("#" + outputDir + targetName + "_trinaryTemplate.zip");
            list.Add("#" + outputDir + targetName + "_syntacticTemplate.zip");
            FileTools.Append2TextFile(templateListPath, list);      //write the template.ZIP file

            //TEST THE TEMPLATE ON SOURCE FILE
            //string[] arguments = new string[3];

            /*
             * var args = new FeltTemplates_Use.Arguments()
             *         {
             *             Source = "",
             * arguments[0] = sourceDir + "\\" + sourceFile;
             * arguments[1] = templateListPath;
             * arguments[2] = listOpDir;
             *
             *         }*/
            //FeltTemplates_Use.Dev(arguments);

            Log.WriteLine("# Finished everything!");
        }