Esempio n. 1
0
        public static void Modify(
            string filename,
            AudioUtilityInfo sourceExpected,
            AudioUtilityRequest request,
            string outputMimeType,
            AudioUtilityInfo outputExpected,
            Action <AudioUtilityInfo, AudioUtilityInfo> additionalTests = null)
        {
            var source = PathHelper.GetTestAudioFile(filename);

            var destExtension  = MediaTypes.GetExtension(outputMimeType);
            var outputFilename = Path.GetFileNameWithoutExtension(filename) + "_modified." + destExtension;

            foreach (var util in new[] { TestHelper.GetAudioUtility() })
            {
                var dir    = PathHelper.GetTempDir();
                var output = new FileInfo(Path.Combine(dir.FullName, outputFilename));

                util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, outputMimeType, request);

                var sourceInfo = util.Info(source);

                TestHelper.CheckAudioUtilityInfo(sourceExpected, sourceInfo);

                var outputInfo     = util.Info(output);
                var outputInfoText = GetDurationInfo(outputInfo);

                additionalTests?.Invoke(sourceExpected, sourceInfo);

                PathHelper.DeleteTempDir(dir);
            }
        }
Esempio n. 2
0
        public void SegmentsWavpackCorrectly3Wavunpack()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromSeconds(55),
                SampleRate    = 22050,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeWav,
                BitsPerSecond = 353000,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono = false,
                OffsetStart   = TimeSpan.FromSeconds(0),
                OffsetEnd     = TimeSpan.FromSeconds(55),

                //SampleRate = 11025
            };

            var source = TestHelper.GetAudioFile("f969b39d-2705-42fc-992c-252a776f1af3_090705-0600.wv");
            var output = PathHelper.GetTempFile(MediaTypes.ExtWav);

            TestHelper.GetAudioUtilityWavunpack().Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = TestHelper.GetAudioUtility().Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
Esempio n. 3
0
        public void SegmentsWavpackCorrectly7Master()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromMinutes(10) + TimeSpan.FromSeconds(0),
                SampleRate    = 17460,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeWav,
                BitsPerSecond = 279000,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono    = true,
                TargetSampleRate = 17460,
            };

            var util = TestHelper.GetAudioUtility();

            var source = TestHelper.GetAudioFile("f969b39d-2705-42fc-992c-252a776f1af3_090705-0600.wv");
            var output = PathHelper.GetTempFile(MediaTypes.ExtWav);

            util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = util.Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
Esempio n. 4
0
        public void SegmentsMp3Correctly2Sox()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromMinutes(3) + TimeSpan.FromSeconds(20),
                SampleRate    = 22050,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeMp3,
                BitsPerSecond = 32000,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono = true,
                OffsetStart   = TimeSpan.FromSeconds(15),
                OffsetEnd     = TimeSpan.FromMinutes(3) + TimeSpan.FromSeconds(35),
            };

            var util = TestHelper.GetAudioUtilitySox();

            var source = TestHelper.GetAudioFile("Currawongs_curlew_West_Knoll_Bees_20091102-183000.mp3");
            var output = PathHelper.GetTempFile(MediaTypes.ExtMp3);

            util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = util.Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
Esempio n. 5
0
        public void SegmentsMp3Correctly6Master()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromSeconds(134.6),
                SampleRate    = 44100,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeMp3,
                BitsPerSecond = 64000,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono    = false,
                Channels         = 2.AsArray(),
                OffsetStart      = TimeSpan.FromSeconds(27),
                TargetSampleRate = 44100,
            };

            var util = TestHelper.GetAudioUtility();

            var source = TestHelper.GetAudioFile("A French Fiddle Speaks.mp3");
            var output = PathHelper.GetTempFile(MediaTypes.ExtMp3);

            util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = util.Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
        public void SegmentsWavCorrectly5Master()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromSeconds(90),
                SampleRate    = 17460,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeWav,
                BitsPerSecond = 279000,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono    = true,
                OffsetStart      = TimeSpan.FromSeconds(27),
                OffsetEnd        = TimeSpan.FromSeconds(117),
                TargetSampleRate = 17460,
            };

            var util = TestHelper.GetAudioUtility();

            var source = TestHelper.GetAudioFile("FemaleKoala MaleKoala.wav");
            var output = PathHelper.GetTempFile(MediaTypes.ExtWav);

            util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = util.Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
Esempio n. 7
0
        public void SegmentsWavCorrectly6Shntool()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromSeconds(93),
                SampleRate    = 17460,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeWav,
                BitsPerSecond = 279000,
            };

            var request = new AudioUtilityRequest
            {
                //MixDownToMono = false,
                //Channel = 2,

                OffsetStart = TimeSpan.FromSeconds(27),

                //TargetSampleRate = 17460,
            };

            var util = TestHelper.GetAudioUtilityShntool();

            var source = TestHelper.GetAudioFile("geckos.wav");
            var output = PathHelper.GetTempFile(MediaTypes.ExtWav);

            util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = util.Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
Esempio n. 8
0
        public void SoxResamplingShouldBeDeterministic()
        {
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromSeconds(60),
                SampleRate    = 22050,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeWav,
                BitsPerSecond = 352800,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono    = true,
                TargetSampleRate = 22050,
            };

            var util = TestHelper.GetAudioUtility();

            var source = TestHelper.GetAudioFile("CaneToad_Gympie_44100.wav");

            var repeats = new double[5][];

            for (int r = 0; r < repeats.Length; r++)
            {
                var output = PathHelper.GetTempFile(MediaTypes.ExtWav);

                util.Modify(source, MediaTypes.GetMediaType(source.Extension), output,
                            MediaTypes.GetMediaType(output.Extension), request);

                var actual = util.Info(output);

                TestHelper.CheckAudioUtilityInfo(expected, actual);

                var reader = new WavReader(output);

                TestHelper.WavReaderAssertions(reader, actual);

                repeats[r] = reader.Samples;

                File.Delete(output.FullName);
            }

            for (int i = 1; i < repeats.Length; i++)
            {
                Assert.AreEqual(repeats[0].Length, repeats[1].Length);

                var totalDifference = 0.0;
                for (int j = 0; j < repeats[0].Length; j++)
                {
                    var delta = Math.Abs(repeats[i][j] - repeats[0][j]);
                    totalDifference += delta;
                }

                CollectionAssert.AreEqual(repeats[0], repeats[i], $"Repeat {i} was not identical to repeat 0. Total delta: {totalDifference}");
            }
        }
        public static FileSegment ToSegment(this AudioUtilityInfo info, FileSegment.FileDateBehavior dateBehavior = FileSegment.FileDateBehavior.Try)
        {
            var source = new FileSegment(
                info.SourceFile,
                info.SampleRate.Value,
                info.Duration.Value,
                dateBehavior);

            return(source);
        }
        protected override void CheckRequestValid(FileInfo source, string sourceMimeType, FileInfo output, string outputMediaType, AudioUtilityRequest request)
        {
            if (AppConfigHelper.IsMacOsX && (sourceMimeType == MediaTypes.MediaTypeMp3 || outputMediaType == MediaTypes.MediaTypeMp3))
            {
                throw new AudioFormatNotSupportedException(Mp3NotSupportedOnOSX);
            }

            AudioUtilityInfo info = null;

            if (request?.BitDepth != null)
            {
                const string message = "Haven't added support for changing bit depth in" + nameof(SoxAudioUtility);
                throw new BitDepthOperationNotImplemented(message);
            }

            // check that if output is mp3, the bit rate and sample rate are set valid amounts.
            if (request != null && outputMediaType == MediaTypes.MediaTypeMp3)
            {
                if (request.TargetSampleRate.HasValue)
                {
                    // sample rate is set - check it
                    this.CheckMp3SampleRate(request.TargetSampleRate.Value);
                }
                else
                {
                    // sample rate is not set, get it from the source file
                    info = this.Info(source);
                    if (!info.SampleRate.HasValue)
                    {
                        throw new ArgumentException("Sample rate for output mp3 may not be correct, as sample rate is not set, and cannot be determined from source file.");
                    }

                    this.CheckMp3SampleRate(info.SampleRate.Value);
                }
            }

            if (request != null && request.Channels.NotNull())
            {
                if (request.Channels.Length == 0)
                {
                    throw new ChannelSelectionOperationNotImplemented("Sox utility cannot choose 0 channels");
                }

                int max = request.Channels.Max();
                int min = request.Channels.Min();
                info ??= this.Info(source);
                if (max > info.ChannelCount || min < 1)
                {
                    var msg = $"Requested channel number was out of range. Requested channel {max} but there are only {info.ChannelCount} channels in {source}.";
                    throw new ChannelNotAvailableException(nameof(request.Channels), request.Channels.ToCommaSeparatedList(), msg);
                }
            }
        }
        private static void DoFrequencyAnalysis(
            AudioUtilityInfo expected,
            int[][] expectedFrequencies)
        {
            var reader = new WavReader(expected.SourceFile);

            TestHelper.WavReaderAssertions(reader, expected);

            for (var channel = 0; channel < expectedFrequencies.Length; channel++)
            {
                var samples = reader.GetChannel(channel);

                TestHelper.AssertFrequencyInSignal(reader, samples, expectedFrequencies[channel]);
            }
        }
Esempio n. 12
0
        public static void WavReaderAssertions(WavReader reader, AudioUtilityInfo info)
        {
            BaseTest.Assert.AreEqual(info.ChannelCount.Value, reader.Channels);
            if (info.BitsPerSample.HasValue)
            {
                BaseTest.Assert.AreEqual(info.BitsPerSample.Value, reader.BitsPerSample);
            }

            BaseTest.Assert.AreEqual(info.SampleRate.Value, reader.SampleRate);
            BaseTest.Assert.AreEqual(info.Duration.Value.TotalMilliseconds, reader.Time.TotalMilliseconds, 150);
            BaseTest.Assert.AreEqual(
                (int)(info.Duration.Value.TotalSeconds * info.SampleRate.Value),
                reader.BlockCount,
                100);
        }
Esempio n. 13
0
        public void ConvertsMp3ToMp3Corectly()
        {
            var expected = new AudioUtilityInfo
            {
                ChannelCount  = 1,
                SampleRate    = 22050,
                Duration      = TimeSpan.FromSeconds(240.031),
                BitsPerSecond = 96000,
                MediaType     = MediaTypes.MediaTypeMp3,
            };

            Modify(
                "Currawongs_curlew_West_Knoll_Bees_20091102-183000.mp3",
                expected,
                new AudioUtilityRequest {
            },
                MediaTypes.MediaTypeMp3,
                expected);
        }
Esempio n. 14
0
        private static string GetDurationInfo(AudioUtilityInfo info)
        {
            var durationText = string.Join(
                ", ",
                info.RawData.Where(
                    l => l.Key.ToLowerInvariant().Contains("duration") || l.Key.ToLowerInvariant().Contains("length")));

            if (info.Duration.HasValue)
            {
                durationText += ", Duration: " + info.Duration;
                durationText  = durationText.Trim(' ', ',');
            }

            //using (var cr = new ConsoleRedirector())
            //{
            //    LoggedConsole.WriteLine(durationText);
            //}

            return(durationText);
        }
Esempio n. 15
0
        public void ConvertsMp3ToWavCorrectly()
        {
            var sourceInfo = TestHelper.AudioDetails["Currawongs_curlew_West_Knoll_Bees_20091102-183000.mp3"];
            var expected   = new AudioUtilityInfo
            {
                ChannelCount  = 1,
                SampleRate    = 22050,
                Duration      = TimeSpan.FromSeconds(240.031),
                BitsPerSecond = 96000,
                MediaType     = MediaTypes.MediaTypeWav,
            };

            Modify(
                "Currawongs_curlew_West_Knoll_Bees_20091102-183000.mp3",
                sourceInfo,
                new AudioUtilityRequest {
            },
                MediaTypes.MediaTypeWav,
                expected);
        }
Esempio n. 16
0
        public static void CheckAudioUtilityInfo(AudioUtilityInfo expected, AudioUtilityInfo actual, int epsilonDurationMilliseconds = 150)
        {
            if (expected.BitsPerSample.HasValue && actual.BitsPerSample.HasValue)
            {
                Assert.AreEqual(expected.BitsPerSample.Value, actual.BitsPerSample.Value);
            }

            if (expected.BitsPerSample.HasValue && !actual.BitsPerSample.HasValue)
            {
                Assert.Fail($"BitsPerSample failed. Expected: {expected.BitsPerSample}, actual: {actual.BitsPerSample}");
            }

            if (expected.BitsPerSecond.HasValue && actual.BitsPerSecond.HasValue)
            {
                // Sox only reports three decimal places and rounds other things
                var actualBps   = (int)((double)actual.BitsPerSecond.Value).RoundToSignificantDigits(3);
                var expectedBps = (int)((double)expected.BitsPerSecond.Value).RoundToSignificantDigits(3);
                Assert.AreEqual(expectedBps, actualBps, 0);
            }

            if (expected.BitsPerSecond.HasValue && !actual.BitsPerSecond.HasValue)
            {
                Assert.Fail($"BitsPerSecond failed. Expected: {expected.BitsPerSecond}, actual: {actual.BitsPerSecond}");
            }

            Assert.IsTrue(!string.IsNullOrWhiteSpace(expected.MediaType));
            Assert.IsTrue(expected.ChannelCount.HasValue);
            Assert.IsTrue(expected.Duration.HasValue);
            Assert.IsTrue(expected.SampleRate.HasValue);

            Assert.IsTrue(!string.IsNullOrWhiteSpace(actual.MediaType));
            Assert.IsTrue(actual.ChannelCount.HasValue);
            Assert.IsTrue(actual.Duration.HasValue);
            Assert.IsTrue(actual.SampleRate.HasValue);

            Assert.AreEqual(expected.MediaType, actual.MediaType);
            Assert.AreEqual(expected.ChannelCount.Value, actual.ChannelCount.Value);
            Assert.AreEqual(expected.Duration.Value.TotalMilliseconds, actual.Duration.Value.TotalMilliseconds, TimeSpan.FromMilliseconds(epsilonDurationMilliseconds).TotalMilliseconds);
            Assert.AreEqual(expected.SampleRate.Value, actual.SampleRate.Value);
        }
        public void SegmentsRawPcmCorrectlyMaster(object startWrapped, object endWrapped, bool mixDown, int expectedChannels, int expectedBitRate)
        {
            double?start = (double?)startWrapped;
            double?end   = (double?)endWrapped;

            var duration = TimeSpan.FromSeconds((end ?? 60.0) - (start ?? 0.0));

            var expected = new AudioUtilityInfo
            {
                Duration      = duration,
                SampleRate    = 44100,
                ChannelCount  = expectedChannels,
                MediaType     = MediaTypes.MediaTypeWav,
                BitsPerSecond = expectedBitRate,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono    = mixDown,
                OffsetStart      = start?.Seconds(),
                OffsetEnd        = end?.Seconds(),
                BitDepth         = 16,
                TargetSampleRate = 44100,
                Channels         = new[] { 1, 2, 3, 4 },
            };

            TestHelper
            .GetAudioUtility()
            .Modify(
                this.source,
                MediaTypes.GetMediaType(this.source.Extension),
                this.output,
                MediaTypes.GetMediaType(this.output.Extension),
                request);

            var actual = TestHelper.GetAudioUtility().Info(this.output);

            TestHelper.CheckAudioUtilityInfo(expected, actual);
        }
Esempio n. 18
0
        public void SegmentsMp3Correctly3Master()
        {
            /*
             *
             * mp3splt accuracy varies with the quality of the input file!
             *
             */
            var expected = new AudioUtilityInfo
            {
                Duration      = TimeSpan.FromSeconds(48),
                SampleRate    = 11025,
                ChannelCount  = 1,
                MediaType     = MediaTypes.MediaTypeMp3,
                BitsPerSecond = 16000,
            };

            var request = new AudioUtilityRequest
            {
                MixDownToMono    = true,
                OffsetStart      = TimeSpan.Zero,
                OffsetEnd        = TimeSpan.FromSeconds(48),
                TargetSampleRate = 11025,
            };

            var util = TestHelper.GetAudioUtility();

            var source = TestHelper.GetAudioFile("Currawongs_curlew_West_Knoll_Bees_20091102-183000.mp3");
            var output = PathHelper.GetTempFile(MediaTypes.ExtMp3);

            util.Modify(source, MediaTypes.GetMediaType(source.Extension), output, MediaTypes.GetMediaType(output.Extension), request);

            var actual = util.Info(output);

            File.Delete(output.FullName);

            TestHelper.CheckAudioUtilityInfo(expected, actual, 380);
        }
Esempio n. 19
0
        /// <summary>
        /// The get info.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="process">
        /// The process.
        /// </param>
        /// <returns>
        /// The Acoustics.Tools.AudioUtilityInfo.
        /// </returns>
        protected override AudioUtilityInfo GetInfo(FileInfo source, ProcessRunner process)
        {
            IEnumerable <string> errorlines = process.ErrorOutput.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

            // if no lines, or any line contains "no handler for file extension", return empty
            if (errorlines.Any(l => l.Contains("no handler for file extension")))
            {
                return(new AudioUtilityInfo());
            }

            IEnumerable <string> lines = process.StandardOutput.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

            var result = new AudioUtilityInfo();

            result.SourceFile = source;

            foreach (var line in lines)
            {
                var firstColon = line.IndexOf(':');

                if (firstColon > -1)
                {
                    var key   = line.Substring(0, firstColon).Trim();
                    var value = line.Substring(firstColon + 1).Trim();

                    if (key == "Duration")
                    {
                        var values = value.Split('=', '~');

                        // duration
                        result.RawData.Add(key, values[0].Trim());

                        // sample count
                        result.RawData.Add("Samples", values[1].Replace("samples", string.Empty).Trim());

                        // approx. CDDA sectors
                        result.RawData.Add("CDDA sectors", values[2].Replace("CDDA sectors", string.Empty).Trim());
                    }
                    else
                    {
                        result.RawData.Add(key, value);
                    }
                }
            }

            // parse info info class
            const string keyDuration   = "Duration";
            const string keySamples    = "Samples";
            const string keyBitRate    = "Bit Rate";
            const string keySampleRate = "Sample Rate";
            const string keyChannels   = "Channels";
            const string keyPrecision  = "Precision";

            if (result.RawData.ContainsKey(keySampleRate))
            {
                result.SampleRate = this.ParseIntStringWithException(result.RawData[keySampleRate], "sox.samplerate");
            }

            if (result.RawData.ContainsKey(keyDuration))
            {
                var sampleCount = result.RawData[keySamples];

                // most precise and efficient calculation, duration from sample count
                if (sampleCount.IsNotEmpty() && result.SampleRate.HasValue)
                {
                    var samples  = this.ParseLongStringWithException(sampleCount, "Samples");
                    var duration = Math.Round((decimal)samples.Value / result.SampleRate.Value, 6, MidpointRounding.AwayFromZero);
                    result.Duration = TimeSpan.FromSeconds((double)duration);
                }
                else
                {
                    // less precise and problematic for very long recordings (because of timespan parsing)
                    // but still faster than another invocation
                    var stringDuration = result.RawData[keyDuration];
                    var formats        = new[]
                    {
                        @"h\:mm\:ss\.ff", @"hh\:mm\:ss\.ff", @"h:mm:ss.ff",
                        @"hh:mm:ss.ff",
                    };

                    if (TimeSpan.TryParseExact(stringDuration.Trim(), formats, CultureInfo.InvariantCulture,
                                               out var duration))
                    {
                        result.Duration = duration;
                    }
                    else
                    {
                        // last resort: ask sox specifically for the duration with another invocation
                        // AT: this case used to always happen even if it was not necessary
                        var extra = this.Duration(source);
                        if (extra.HasValue)
                        {
                            result.Duration = extra.Value;
                        }
                    }
                }
            }

            if (result.RawData.ContainsKey(keyChannels))
            {
                result.ChannelCount = this.ParseIntStringWithException(result.RawData[keyChannels], "sox.channels");
            }

            if (result.RawData.ContainsKey(keyPrecision))
            {
                result.BitsPerSample = this.ParseIntStringWithException(result.RawData[keyPrecision].Replace("-bit", string.Empty).Trim(), "sox.precision");
                if (result.BitsPerSample < 1)
                {
                    result.BitsPerSample = null;
                }
            }

            result.MediaType = GetMediaType(result.RawData, source.Extension);

            if (result.RawData.ContainsKey(keyBitRate))
            {
                var stringValue = result.RawData[keyBitRate];

                int magnitude = 1;

                if (stringValue.Contains("k"))
                {
                    stringValue = stringValue.Replace("k", string.Empty);
                    magnitude   = 1000;
                }

                if (stringValue.Contains("M"))
                {
                    stringValue = stringValue.Replace("M", string.Empty);
                    magnitude   = 1_000_000;
                }

                if (stringValue.Contains("G") || stringValue.Contains("T"))
                {
                    throw new NotSupportedException(
                              $"The file {source.FullName} reported a bit rate of {stringValue} which is not supported");
                }

                var value = double.Parse(stringValue, CultureInfo.InvariantCulture);

                value = value * magnitude;

                result.BitsPerSecond = Convert.ToInt32(value);

                // Further investigation reveals the 'error' I was chasing down was in fact the difference
                // between the FormatBitRate (averaged inc. header) and the StreamBitRate.
                // For long files this difference approaches 0, for short files the difference is significant
                //if (result.MediaType == MediaTypes.MediaTypeWav)
                //{
                //    // deal with inaccuracy - calculate it a second way
                //    var estimatedBitRate = result.SampleRate * result.ChannelCount * result.BitsPerSample;
                //    int roundedBitRate = (int)((double)estimatedBitRate).RoundToSignficantDigits(3);
                //    if (roundedBitRate != result.BitsPerSecond.Value)
                //    {
                //        throw new InvalidOperationException(
                //            $"SoxAudioUtlity could not accurately predict BitPerSecond. Parsed BitsPerSecond: {result.BitsPerSecond}, predicted: {estimatedBitRate}");
                //    }
                //
                //    // use estimated bit rate
                //    result.BitsPerSecond = estimatedBitRate;
                //}
            }

            return(result);
        }
Esempio n. 20
0
        private AudioUtilityInfo Combine(AudioUtilityInfo info, AudioUtilityInfo extra)
        {
            var result = new AudioUtilityInfo();

            if (info == null && extra == null)
            {
                return(result);
            }

            if (info == null)
            {
                return(extra);
            }

            if (extra == null)
            {
                return(info);
            }

            // source file
            if (info.SourceFile != null && extra.SourceFile != null && info.SourceFile != extra.SourceFile)
            {
                throw new InvalidOperationException(string.Format("Source files must be the same: {0} != {1}.", info.SourceFile, extra.SourceFile));
            }
            if (info.SourceFile != null)
            {
                result.SourceFile = info.SourceFile;
            }
            else if (extra.SourceFile != null)
            {
                result.SourceFile = extra.SourceFile;
            }

            // bits per sample
            if (info.BitsPerSample.HasValue)
            {
                result.BitsPerSample = info.BitsPerSample;
            }
            else if (extra.BitsPerSample.HasValue)
            {
                result.BitsPerSample = extra.BitsPerSample;
            }

            // bits per second
            if (info.BitsPerSecond.HasValue)
            {
                result.BitsPerSecond = info.BitsPerSecond;
            }
            else if (extra.BitsPerSecond.HasValue)
            {
                result.BitsPerSecond = extra.BitsPerSecond;
            }

            // channel count
            if (info.ChannelCount.HasValue)
            {
                result.ChannelCount = info.ChannelCount;
            }
            else if (extra.ChannelCount.HasValue)
            {
                result.ChannelCount = extra.ChannelCount;
            }

            // duration
            if (info.Duration.HasValue)
            {
                result.Duration = info.Duration;
            }
            else if (extra.Duration.HasValue)
            {
                result.Duration = extra.Duration;
            }

            // media type
            if (!string.IsNullOrWhiteSpace(info.MediaType))
            {
                result.MediaType = info.MediaType;
            }
            else if (!string.IsNullOrWhiteSpace(extra.MediaType))
            {
                result.MediaType = extra.MediaType;
            }

            // sample rate
            if (info.SampleRate.HasValue)
            {
                result.SampleRate = info.SampleRate;
            }
            else if (extra.SampleRate.HasValue)
            {
                result.SampleRate = extra.SampleRate;
            }

            // combine raw data
            if (info.RawData != null)
            {
                foreach (var item in info.RawData)
                {
                    result.RawData.Add(item.Key, item.Value);
                }
            }

            if (extra.RawData != null)
            {
                foreach (var item in extra.RawData)
                {
                    result.RawData.Add(item.Key, item.Value);
                }
            }

            return(result);
        }
Esempio n. 21
0
        /// <summary>
        /// The get info.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="process">
        /// The process.
        /// </param>
        /// <returns>
        /// The Acoustics.Tools.AudioUtilityInfo.
        /// </returns>
        protected override AudioUtilityInfo GetInfo(FileInfo source, ProcessRunner process)
        {
            var result = new AudioUtilityInfo();

            var std = process.StandardOutput;

            const string Length          = "Length:";
            const string Channels        = "Channels:";
            const string BitsPerSample   = "Bits/sample:";
            const string SamplePerSecond = "Samples/sec:";
            const string FileName        = "File name:";
            const string BitsPerSecond   = "Average bytes/sec:";
            const string WavDataSize     = "Data size:";

            long wavDataSizeBytes = 0;

            foreach (var line in std.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (line.StartsWith(Length))
                {
                    result.Duration = Parse(line.Replace(Length, string.Empty).Trim());
                }

                if (line.StartsWith(Channels))
                {
                    result.ChannelCount = this.ParseIntStringWithException(line.Replace(Channels, string.Empty).Trim(), "shntool.channels");
                }

                if (line.StartsWith(BitsPerSample))
                {
                    result.BitsPerSample = this.ParseIntStringWithException(line.Replace(BitsPerSample, string.Empty).Trim(), "shntool.bitspersample");
                }

                if (line.StartsWith(SamplePerSecond))
                {
                    result.SampleRate = this.ParseIntStringWithException(line.Replace(SamplePerSecond, string.Empty).Trim(), "shntool.samplespersecond");
                }

                if (line.StartsWith(FileName))
                {
                    result.SourceFile = new FileInfo(line.Replace(FileName, string.Empty).Trim());
                }

                if (line.StartsWith(BitsPerSecond))
                {
                    // convert bytes to bits
                    result.BitsPerSecond = this.ParseIntStringWithException(line.Replace(BitsPerSecond, string.Empty).Trim(), "shntool.BitsPerSecond") * 8;
                }

                if (line.StartsWith(WavDataSize))
                {
                    wavDataSizeBytes = this.ParseLongStringWithException(
                        line.Replace(WavDataSize, string.Empty).Replace("bytes", string.Empty).Trim(),
                        "shntool.DataSize").Value;
                }

                result.MediaType = MediaTypes.MediaTypeWav;

                if (line.Contains(":"))
                {
                    result.RawData.Add(
                        line.Substring(0, line.IndexOf(":", StringComparison.Ordinal)).Trim(),
                        line.Substring(line.IndexOf(":", StringComparison.Ordinal) + 1).Trim());
                }
            }

            // shntool is bloody annoying - for CD quality files it estimates the duration to print out.
            // See http://linux.die.net/man/1/shntool, https://github.com/flacon/shntool/blob/4c6fc2e58c830080f6f9112935325ad281b784ff/src/core_wave.c#L268
            // and https://github.com/flacon/shntool/blob/4c6fc2e58c830080f6f9112935325ad281b784ff/src/core_mode.c#L781
            // for explanations.
            // For now, we just have to sanity check it's reported duration.

            // exact duration = dataSize * 8 / bitrate
            // bitrate = samplesPerSecond * channels * bitsPerSample
            var bitrate       = result.SampleRate.Value * result.ChannelCount.Value * result.BitsPerSample.Value;
            var exactDuration = TimeSpan.FromSeconds((double)(wavDataSizeBytes * 8) / bitrate);

            if (exactDuration - result.Duration.Value > TimeSpan.FromMilliseconds(100))
            {
                this.Log.Warn("Shntool reported a bad duration because it parsed a file as CD quality. Actual duration has been returned");
                result.Duration = exactDuration;
            }

            return(result);
        }
Esempio n. 22
0
        /// <summary>
        /// The get info.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="process">
        /// The process.
        /// </param>
        /// <returns>
        /// The Acoustics.Tools.AudioUtilityInfo.
        /// </returns>
        protected override AudioUtilityInfo GetInfo(FileInfo source, ProcessRunner process)
        {
            var lines = process.StandardOutput.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            var result = new AudioUtilityInfo();

            result.SourceFile = source;

            foreach (var line in lines)
            {
                var firstColon = line.IndexOf(':');

                if (firstColon > -1)
                {
                    var key   = line.Substring(0, firstColon).Trim();
                    var value = line.Substring(firstColon + 1).Trim();

                    if (key == "source")
                    {
                        var values = value.Split(' ');

                        // precision
                        result.RawData.Add("precision", values[0].Trim());

                        // sample rate
                        result.RawData.Add("sample rate", values[3].Trim());
                    }
                    else
                    {
                        result.RawData.Add(key, value);
                    }
                }
            }

            // parse info into class
            const string KeyDuration   = "duration";
            const string KeyBitRate    = "ave bitrate";
            const string KeySampleRate = "sample rate";
            const string KeyChannels   = "channels";
            const string KeyPrecision  = "precision";

            if (result.RawData.ContainsKey(KeyDuration))
            {
                var stringDuration = result.RawData[KeyDuration];

                var formats = new[]
                {
                    @"h\:mm\:ss\.ff", @"hh\:mm\:ss\.ff", @"h:mm:ss.ff",
                    @"hh:mm:ss.ff",
                };

                TimeSpan tsresult;
                if (TimeSpan.TryParseExact(stringDuration.Trim(), formats, CultureInfo.InvariantCulture, out tsresult))
                {
                    result.Duration = tsresult;
                }
            }

            if (result.RawData.ContainsKey(KeyBitRate))
            {
                var stringValue = result.RawData[KeyBitRate];

                var hadK = false;
                if (stringValue.Contains("kbps"))
                {
                    stringValue = stringValue.Replace("kbps", string.Empty);
                    hadK        = true;
                }

                var value = double.Parse(stringValue);

                if (hadK)
                {
                    value = value * 1000;
                }

                result.BitsPerSecond = Convert.ToInt32(value);
            }

            if (result.RawData.ContainsKey(KeySampleRate))
            {
                result.SampleRate = this.ParseIntStringWithException(result.RawData[KeySampleRate], "wavPack.SampleRate");
            }

            if (result.RawData.ContainsKey(KeyChannels))
            {
                // multi channel will attempt to print the channel names "4 (FL,FR,FC,LFE)"
                string channels = result.RawData[KeyChannels];
                channels = Regex.Replace(channels, "\\(.*\\).*", string.Empty).Trim();

                result.ChannelCount = this.ParseIntStringWithException(channels, "wavPack.Channels");
            }

            if (result.RawData.ContainsKey(KeyPrecision))
            {
                result.BitsPerSample = this.ParseIntStringWithException(result.RawData[KeyPrecision].Replace("-bit", string.Empty).Trim(), "wavPack.Precision");
            }

            result.MediaType = MediaTypes.MediaTypeWavpack;

            return(result);
        }
Esempio n. 23
0
        /// <summary>
        /// The get info.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="process">
        /// The process.
        /// </param>
        /// <returns>
        /// The Acoustics.Tools.AudioUtilityInfo.
        /// </returns>
        protected override AudioUtilityInfo GetInfo(FileInfo source, ProcessRunner process)
        {
            var result = new AudioUtilityInfo();

            result.SourceFile = source;

            // parse output
            ////var err = process.ErrorOutput;
            var    std = process.StandardOutput;
            string currentBlockName = string.Empty;

            foreach (var line in std.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (line.StartsWith("[/") && line.EndsWith("]"))
                {
                    // end of a block
                }
                else if (line.StartsWith("[") && line.EndsWith("]"))
                {
                    // start of a block
                    currentBlockName = line.Trim('[', ']');
                }
                else
                {
                    // key=value
                    var key   = currentBlockName + " " + line.Substring(0, line.IndexOf('='));
                    var value = line.Substring(line.IndexOf('=') + 1);
                    result.RawData.Add(key.Trim(), value.Trim());
                }
            }

            // parse info info class
            var keyDuration         = "FORMAT duration";
            var keyBitRate          = "FORMAT bit_rate";
            var keySampleRate       = "STREAM sample_rate";
            var keyChannels         = "STREAM channels";
            var keyBitsPerSample    = "STREAM bits_per_sample";
            var keyBitsPerRawSample = "STREAM bits_per_raw_sample";

            if (result.RawData.ContainsKey(keyDuration))
            {
                var stringDuration = result.RawData[keyDuration];

                double?samples = this.ParseDoubleStringWithException(stringDuration.Trim(), keyDuration);

                result.Duration = TimeSpan.FromSeconds(samples.Value);
            }

            result.BitsPerSecond = GetBitRate(result.RawData);

            if (result.RawData.ContainsKey(keyBitRate))
            {
                result.BitsPerSecond = this.ParseIntStringWithException(result.RawData[keyBitRate], "ffmpeg.bitrate", new string[] { NotApplicable });
            }

            if (result.RawData.ContainsKey(keySampleRate))
            {
                result.SampleRate = this.ParseIntStringWithException(result.RawData[keySampleRate], "ffmpeg.samplerate", new string[] { NotApplicable });
            }

            if (result.RawData.ContainsKey(keyChannels))
            {
                result.ChannelCount = this.ParseIntStringWithException(result.RawData[keyChannels], "ffmpeg.channels", new string[] { NotApplicable });
            }

            if (result.RawData.ContainsKey(keyBitsPerSample))
            {
                result.BitsPerSample = this.ParseIntStringWithException(
                    result.RawData[keyBitsPerSample],
                    "ffmpeg.bitspersample",
                    new[] { NotApplicable });

                if (result.BitsPerSample < 1)
                {
                    result.BitsPerSample = null;
                }

                if (result.BitsPerSample == null)
                {
                    result.BitsPerSample = this.ParseIntStringWithException(
                        result.RawData[keyBitsPerRawSample],
                        "ffmpeg.bitsperrawsample",
                        new[] { NotApplicable });
                }

                if (result.BitsPerSample < 1)
                {
                    result.BitsPerSample = null;
                }
            }

            result.MediaType = this.GetMediaType(result.RawData, source.Extension);
            //FfmpegFormatToMediaType(result.RawData, source.Extension);

            return(result);
        }