public MainWindow()
        {
            InitializeComponent();

            try
            {
                this.logger = Gnosis.Utilities.Log4NetLogger.GetDefaultLogger(typeof(MainWindow));
            }
            catch (Exception loggerEx)
            {
                throw new ApplicationException("Could not initialize logger", loggerEx);
            }

            try
            {
                logger.Info("Initializing Alexandria");

                mediaFactory    = new MediaFactory(logger);
                securityContext = new SecurityContext(mediaFactory);
                tagTypeFactory  = new TagTypeFactory();

                mediaRepository = new SQLiteMediaRepository(logger, mediaFactory);
                mediaRepository.Initialize();

                linkRepository = new SQLiteLinkRepository(logger);
                linkRepository.Initialize();

                tagRepository = new SQLiteTagRepository(logger, tagTypeFactory);
                tagRepository.Initialize();

                metadataRepository = new SQLiteMetadataRepository(logger, securityContext, mediaFactory);
                metadataRepository.Initialize();

                marqueeRepository = new SQLiteMarqueeRepository(logger);

                audioStreamFactory = new AudioStreamFactory();

                videoPlayer = new Gnosis.Video.Vlc.VideoPlayerControl();
                videoPlayer.Initialize(logger, () => GetVideoHost());

                catalogController = new CatalogController(logger, securityContext, mediaFactory, mediaRepository, linkRepository, tagRepository, metadataRepository, audioStreamFactory);
                spiderFactory     = new SpiderFactory(logger, securityContext, mediaFactory, linkRepository, tagRepository, mediaRepository, metadataRepository, audioStreamFactory);

                metadataController = new MediaItemController(logger, securityContext, mediaFactory, linkRepository, tagRepository, metadataRepository);
                taskController     = new TaskController(logger, mediaFactory, videoPlayer, spiderFactory, metadataController, marqueeRepository, metadataRepository);
                tagController      = new TagController(logger, tagRepository);
                commandController  = new CommandController(logger);

                taskResultView.Initialize(logger, securityContext, mediaFactory, metadataController, taskController, tagController, videoPlayer);
                //taskManagerView.Initialize(logger, taskController, taskResultView);
                searchView.Initialize(logger, taskController, taskResultView);
                commandView.Initialize(logger, commandController, taskController, taskResultView);

                ScreenSaver.Disable();
            }
            catch (Exception ex)
            {
                logger.Error("MainWindow.ctor", ex);
            }
        }
Beispiel #2
0
 private void AddConcatenatedFiles(List <FileInfo> fileInfos)
 {
     if (fileInfos.Select(fi => AudioStreamFactory.IsSupportedFile(fi.FullName)).Count() == fileInfos.Count)
     {
         AudioTrack audioTrack = new AudioTrack(fileInfos.ToArray());
         trackList.Add(audioTrack);
     }
 }
Beispiel #3
0
 private void AddFile(string fileName)
 {
     if (AudioStreamFactory.IsSupportedFile(fileName))
     {
         AudioTrack audioTrack = new AudioTrack(new FileInfo(fileName));
         trackListBox.Items.Add(audioTrack);
     }
 }
Beispiel #4
0
 private void AddFile(FileInfo fileInfo)
 {
     try {
         AudioStreamFactory.IsSupportedFileOrThrow(fileInfo.FullName);
         AudioTrack audioTrack = new AudioTrack(fileInfo);
         trackList.Add(audioTrack);
     } catch (Exception e) {
         MessageBox.Show(this, e.Message, "Cannot open file: " + fileInfo.Name, MessageBoxButton.OK, MessageBoxImage.Error);
     }
 }
Beispiel #5
0
        private void SetAudioTrack(AudioTrack audioTrack)
        {
            UnsetAudioTrack();

            this.audioTrack              = audioTrack;
            audioStream                  = AudioStreamFactory.FromAudioTrackForGUI(audioTrack);
            audioStream.WaveformChanged += OnAudioStreamWaveformChanged;
            audioTrack.LengthChanged    += OnAudioTrackLengthChanged;
            audioTrack.VolumeChanged    += OnAudioTrackVolumeChanged;
            audioTrack.BalanceChanged   += OnAudioTrackBalanceChanged;
        }
Beispiel #6
0
        public MainWindow()
        {
            InitializeComponent();

            // Use PFFFT as FFT implementation
            FFTFactory.Factory = new Aurio.PFFFT.FFTFactory();
            // Use Soxr as resampler implementation
            ResamplerFactory.Factory = new Aurio.Soxr.ResamplerFactory();
            // Use FFmpeg for file reading/decoding
            AudioStreamFactory.AddFactory(new FFmpegAudioStreamFactory());
        }
Beispiel #7
0
        public void Generate()
        {
            IAudioStream audioStream = inputTrack.File ?
                                       AudioStreamFactory.FromFileInfoIeee32(inputTrack.FileInfo) :
                                       inputTrack.Stream;

            audioStream = new MonoStream(audioStream);
            audioStream = new ResamplingStream(audioStream, ResamplingQuality.Medium, profile.SampleRate);

            STFT stft = new STFT(audioStream, profile.FrameSize, profile.FrameStep, WindowType.Hann, STFT.OutputFormat.Decibel, this.bufferSize);

            index   = 0;
            indices = stft.WindowCount;

            frameBuffer = new float[profile.FrameSize / 2];
            List <SubFingerprint> subFingerprints = new List <SubFingerprint>();

            while (stft.HasNext())
            {
                // Get FFT spectrum
                stft.ReadFrame(frameBuffer);

                // Sum FFT bins into target frequency bands
                profile.MapFrequencies(frameBuffer, bands);

                CalculateSubFingerprint(bandsPrev, bands, subFingerprints);

                CommonUtil.Swap <float[]>(ref bands, ref bandsPrev);
                index++;

                // Output subfingerprints every once in a while
                if (index % this.eventInterval == 0 && SubFingerprintsGenerated != null)
                {
                    SubFingerprintsGenerated(this, new SubFingerprintsGeneratedEventArgs(inputTrack, subFingerprints, index, indices));
                    subFingerprints.Clear();
                }
            }

            // Output remaining subfingerprints
            if (SubFingerprintsGenerated != null)
            {
                SubFingerprintsGenerated(this, new SubFingerprintsGeneratedEventArgs(inputTrack, subFingerprints, index, indices));
            }

            if (Completed != null)
            {
                Completed(this, EventArgs.Empty);
            }

            audioStream.Close();
        }
Beispiel #8
0
        public IAudioStream CreateAudioStream()
        {
            IAudioStream stream = null;

            if (MultiFile)
            {
                stream = new ConcatenationStream(FileInfos.Select(fi => AudioStreamFactory.FromFileInfoIeee32(fi)).ToArray());
            }
            else
            {
                stream = AudioStreamFactory.FromFileInfoIeee32(FileInfo);
            }
            return(new TimeWarpStream(stream, timeWarps));
        }
        public IAudioStream OpenFile(FileInfo fileInfo)
        {
            if (FFmpegSourceStream.WaveProxySuggested(fileInfo))
            {
                Console.WriteLine("File format with known seek problems, creating proxy file...");
                return(AudioStreamFactory.FromFileInfo(FFmpegSourceStream.CreateWaveProxy(fileInfo)));
            }
            else
            {
                try
                {
                    FFmpegSourceStream stream = new FFmpegSourceStream(fileInfo);

                    // Make a seek to test if it works or if it throws an exception
                    stream.Position = 0;

                    return(stream);
                }
                catch (FFmpegSourceStream.FileNotSeekableException)
                {
                    /*
                     * This exception gets thrown if a file is not seekable and therefore cannot
                     * provide all the functionality that is needed for an IAudioStream, although
                     * the problem could be solved by creating a seek index. See FFmpegSourceStream
                     * for further information.
                     *
                     * For now, we create a WAV proxy file, because it is easier (consumes
                     * additional space though).
                     */
                    Console.WriteLine("File not seekable, creating proxy file...");
                    return(AudioStreamFactory.FromFileInfo(FFmpegSourceStream.CreateWaveProxy(fileInfo)));
                }
                catch (FFmpegSourceStream.FileSeekException)
                {
                    /*
                     * This exception gets thrown if a file should be seekable but seeking still does
                     * not work correctly. We also create a proxy in this case.
                     */
                    Console.WriteLine("File test seek failed, creating proxy file...");
                    return(AudioStreamFactory.FromFileInfo(FFmpegSourceStream.CreateWaveProxy(fileInfo)));
                }
                catch (DllNotFoundException e)
                {
                    throw new DllNotFoundException("Cannot open file through FFmpeg: DLL missing", e);
                }
            }
        }
Beispiel #10
0
        private static void Main(string[] args)
        {
            // Use PFFFT as FFT implementation
            FFTFactory.Factory = new Aurio.PFFFT.FFTFactory();
            // Use Soxr as resampler implementation
            ResamplerFactory.Factory = new Aurio.Soxr.ResamplerFactory();
            // Use FFmpeg for file reading/decoding
            AudioStreamFactory.AddFactory(new FFmpegAudioStreamFactory());

            try
            {
                // read config file
                Dictionary <string, double> mapping = ReadConfig(args[0]);

                // read input dir
                DirectoryInfo indir = new DirectoryInfo(args[1]);

                // read output dir
                DirectoryInfo outdir = new DirectoryInfo(args[2]);
                if (!outdir.Exists)
                {
                    outdir.Create();
                }

                Process(mapping, indir, outdir);
            }
            catch (Exception e)
            {
                Console.WriteLine("Batch Resampling Tool to change the playback speed of audio files");
                Console.WriteLine();
                Console.WriteLine("Error: " + e.Message);
                Console.WriteLine();

                var info = "Usage: BatchResampler mappingFile inputDirectory outputDirectory" + Environment.NewLine +
                           Environment.NewLine +
                           "The mappingFile is a text file with at least one line of the pattern 'filenamePattern;resamplingFactor' (without quotes), " +
                           "where the filenamePattern can be a filename or a filename wildcard expression to be matched in the input directory, and the " +
                           "resamplingFactor is a floating point value specifying the input:output resampling ratio with which the files will be written" +
                           "to the output directory. The simplest mappingFile would be '*;1', which means that all files in the input directory will be" +
                           "resampled with a factor of 1.0 (i.e. no resampling at all) and written to the output directory. The nominal sampling rate of a file" +
                           "stays untouched, leading to altered playback speeds." + Environment.NewLine +
                           "A mappingFile with the content '*.wav;0.5' speeds up all wave audio files to 200% playback speed because they are getting resampled " +
                           "to half of their effective sampling rate while the nominal playback sample rate stays the same, cutting their playback duration in half.";

                Console.WriteLine(info);
            }
        }
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker     = sender as BackgroundWorker;
            Parameters       parameters = (Parameters)e.Argument;

            var streams = parameters.SourceFiles.Select(fi => AudioStreamFactory.FromFileInfo(fi));

            // load source stream
            var sourceStream = new ConcatenationStream(streams.ToArray());

            var    firstFile            = parameters.SourceFiles.First();
            string targetFileNamePrefix = firstFile.FullName.Remove(firstFile.FullName.Length - firstFile.Extension.Length);
            string targetFileNameSuffix = firstFile.Extension;

            int        partCount  = 0;
            Random     random     = new Random();
            CropStream cropStream = new CropStream(sourceStream, 0, 0);

            while (sourceStream.Position < sourceStream.Length)
            {
                partCount++;
                int  length     = random.Next(parameters.MinLength, parameters.MaxLength); // length in seconds of the current part to write
                long byteLength = TimeUtil.TimeSpanToBytes(new TimeSpan(TimeUtil.SECS_TO_TICKS * length), cropStream.Properties);

                Debug.WriteLine("writing part " + partCount + " (" + length + " secs = " + byteLength + " bytes)");
                Debug.WriteLine("before: " + cropStream.Begin + " / " + cropStream.End + " / " + cropStream.Position + " / " + sourceStream.Position);
                cropStream.Begin    = cropStream.End;
                cropStream.End     += sourceStream.Length - cropStream.Begin < byteLength ? sourceStream.Length - cropStream.Begin : byteLength;
                cropStream.Position = 0;
                Debug.WriteLine("after : " + cropStream.Begin + " / " + cropStream.End + " / " + cropStream.Position + " / " + sourceStream.Position);
                AudioStreamFactory.WriteToFile(cropStream, String.Format("{0}.part{1:000}{2}", targetFileNamePrefix, partCount, targetFileNameSuffix));

                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    Debug.WriteLine("canceled");
                    return;
                }
                worker.ReportProgress((int)((double)sourceStream.Position / sourceStream.Length * 100));
            }
            Debug.WriteLine("finished");
        }
Beispiel #12
0
        static void Process(Dictionary <string, double> mapping, DirectoryInfo indir, DirectoryInfo outdir)
        {
            Dictionary <FileInfo, double> fileMapping = new Dictionary <FileInfo, double>();

            foreach (string fileNamePattern in mapping.Keys)
            {
                double factor = mapping[fileNamePattern];
                foreach (FileInfo fileInfo in indir.EnumerateFiles(fileNamePattern))
                {
                    fileMapping.Add(fileInfo, factor);
                }
            }

            Parallel.ForEach <FileInfo>(fileMapping.Keys, (fileInfo) => {
                double factor           = fileMapping[fileInfo];
                FileInfo outputFileInfo = new FileInfo(Path.Combine(outdir.FullName, fileInfo.Name));

                if (outputFileInfo.Exists)
                {
                    Console.WriteLine(fileInfo.Name + " SKIP (file already existing)");
                    return;
                }

                Console.WriteLine(fileInfo.Name);
                try
                {
                    IAudioStream inputStream          = AudioStreamFactory.FromFileInfoIeee32(fileInfo);
                    IAudioStream resamplingStream     = new ResamplingStream(inputStream, ResamplingQuality.VeryHigh, factor);
                    MixerStream sampleRateResetStream = new MixerStream(resamplingStream.Properties.Channels, inputStream.Properties.SampleRate);
                    sampleRateResetStream.Add(resamplingStream);

                    IAudioStream outputStream = sampleRateResetStream;

                    AudioStreamFactory.WriteToFile(outputStream, outputFileInfo.FullName);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error processing " + fileInfo.Name + ": " + e.Message);
                }
            });
        }
Beispiel #13
0
 public AudioTrack(FileInfo[] fileInfos, bool initialize)
     : base(fileInfos)
 {
     this.TimeWarps = new TimeWarpCollection();
     if (initialize)
     {
         using (IAudioStream stream = AudioStreamFactory.FromFileInfo(FileInfo)) {
             sourceProperties = stream.Properties;
             if (MultiFile)
             {
                 // For multi-file tracks, we need to get a concatenated stream of all files for the length
                 InitializeLength();
             }
             else
             {
                 // Single-file tracks can just reuse this stream to get the length
                 InitializeLength(stream);
             }
         }
     }
 }
Beispiel #14
0
        private void SetAudioTrack(AudioTrack audioTrack)
        {
            UnsetAudioTrack();

            // init renderers
            waveformBitmapRenderers = new WaveformBitmapRenderer[audioTrack.SourceProperties.Channels];
            for (int i = 0; i < waveformBitmapRenderers.Length; i++)
            {
                waveformBitmapRenderers[i] = new WaveformBitmapRenderer();
            }
            waveformGeometryRenderers = new WaveformGeometryRenderer[audioTrack.SourceProperties.Channels];
            for (int i = 0; i < waveformGeometryRenderers.Length; i++)
            {
                waveformGeometryRenderers[i] = new WaveformGeometryRenderer();
            }

            this.audioTrack              = audioTrack;
            audioStream                  = AudioStreamFactory.FromAudioTrackForGUI(audioTrack);
            audioStream.WaveformChanged += OnAudioStreamWaveformChanged;
            audioTrack.LengthChanged    += OnAudioTrackLengthChanged;
            audioTrack.VolumeChanged    += OnAudioTrackVolumeChanged;
            audioTrack.BalanceChanged   += OnAudioTrackBalanceChanged;
        }
Beispiel #15
0
        public void Generate(AudioTrack track)
        {
            IAudioStream audioStream = new ResamplingStream(
                new MonoStream(AudioStreamFactory.FromFileInfoIeee32(track.FileInfo)),
                ResamplingQuality.Medium, profile.SamplingRate);

            STFT stft            = new STFT(audioStream, profile.WindowSize, profile.HopSize, WindowType.Hann, STFT.OutputFormat.Decibel);
            int  index           = 0;
            int  indices         = stft.WindowCount;
            int  processedFrames = 0;

            float[] spectrum         = new float[profile.WindowSize / 2];
            float[] smoothedSpectrum = new float[spectrum.Length - profile.SpectrumSmoothingLength + 1]; // the smooved frequency spectrum of the current frame
            var     spectrumSmoother = new SimpleMovingAverage(profile.SpectrumSmoothingLength);

            float[] spectrumTemporalAverage = new float[spectrum.Length]; // a running average of each spectrum bin over time
            float[] spectrumResidual        = new float[spectrum.Length]; // the difference between the current spectrum and the moving average spectrum

            var peakHistory = new PeakHistory(1 + profile.TargetZoneDistance + profile.TargetZoneLength, spectrum.Length / 2);
            var peakPairs   = new List <PeakPair>(profile.PeaksPerFrame * profile.PeakFanout); // keep a single instance of the list to avoid instantiation overhead

            var subFingerprints = new List <SubFingerprint>();

            while (stft.HasNext())
            {
                // Get the FFT spectrum
                stft.ReadFrame(spectrum);

                // Skip frames whose average spectrum volume is below the threshold
                // This skips silent frames (zero samples) that only contain very low noise from the FFT
                // and that would screw up the temporal spectrum average below for the following frames.
                if (spectrum.Average() < spectrumMinThreshold)
                {
                    index++;
                    continue;
                }

                // Smooth the frequency spectrum to remove small peaks
                if (profile.SpectrumSmoothingLength > 0)
                {
                    spectrumSmoother.Clear();
                    for (int i = 0; i < spectrum.Length; i++)
                    {
                        var avg = spectrumSmoother.Add(spectrum[i]);
                        if (i >= profile.SpectrumSmoothingLength)
                        {
                            smoothedSpectrum[i - profile.SpectrumSmoothingLength] = avg;
                        }
                    }
                }

                // Update the temporal moving bin average
                if (processedFrames == 0)
                {
                    // Init averages on first frame
                    for (int i = 0; i < spectrum.Length; i++)
                    {
                        spectrumTemporalAverage[i] = spectrum[i];
                    }
                }
                else
                {
                    // Update averages on all subsequent frames
                    for (int i = 0; i < spectrum.Length; i++)
                    {
                        spectrumTemporalAverage[i] = ExponentialMovingAverage.UpdateMovingAverage(
                            spectrumTemporalAverage[i], profile.SpectrumTemporalSmoothingCoefficient, spectrum[i]);
                    }
                }

                // Calculate the residual
                // The residual is the difference of the current spectrum to the temporal average spectrum. The higher
                // a bin residual is, the steeper the increase in energy in that peak.
                for (int i = 0; i < spectrum.Length; i++)
                {
                    spectrumResidual[i] = spectrum[i] - spectrumTemporalAverage[i] - 90f;
                }

                // Find local peaks in the residual
                // The advantage of finding peaks in the residual instead of the spectrum is that spectrum energy is usually
                // concentrated in the low frequencies, resulting in a clustering of the highest peaks in the lows. Getting
                // peaks from the residual distributes the peaks more evenly across the spectrum.
                var peaks = peakHistory.List;             // take oldest list,
                peaks.Clear();                            // clear it, and
                FindLocalMaxima(spectrumResidual, peaks); // refill with new peaks

                // Pick the largest n peaks
                int numMaxima = Math.Min(peaks.Count, profile.PeaksPerFrame);
                if (numMaxima > 0)
                {
                    peaks.Sort((p1, p2) => p1.Value == p2.Value ? 0 : p1.Value < p2.Value ? 1 : -1); // order peaks by height
                    if (peaks.Count > numMaxima)
                    {
                        peaks.RemoveRange(numMaxima, peaks.Count - numMaxima);                       // select the n tallest peaks by deleting the rest
                    }
                    peaks.Sort((p1, p2) => p1.Index == p2.Index ? 0 : p1.Index < p2.Index ? -1 : 1); // sort peaks by index (not really necessary)
                }

                peakHistory.Add(index, peaks);

                if (FrameProcessed != null)
                {
                    // Mark peaks as 0dB for spectrogram display purposes
                    foreach (var peak in peaks)
                    {
                        spectrum[peak.Index]         = 0;
                        spectrumResidual[peak.Index] = 0;
                    }

                    FrameProcessed(this, new FrameProcessedEventArgs {
                        AudioTrack = track, Index = index, Indices = indices,
                        Spectrum   = spectrum, SpectrumResidual = spectrumResidual
                    });
                }

                processedFrames++;
                index++;

                if (processedFrames >= peakHistory.Length)
                {
                    peakPairs.Clear();
                    FindPairsWithMaxEnergy(peakHistory, peakPairs);
                    ConvertPairsToSubFingerprints(peakPairs, subFingerprints);
                }

                if (subFingerprints.Count > 512)
                {
                    FireFingerprintHashesGenerated(track, indices, subFingerprints);
                    subFingerprints.Clear();
                }
            }

            // Flush the remaining peaks of the last frames from the history to get all remaining pairs
            for (int i = 0; i < profile.TargetZoneLength; i++)
            {
                var peaks = peakHistory.List;
                peaks.Clear();
                peakHistory.Add(-1, peaks);
                peakPairs.Clear();
                FindPairsWithMaxEnergy(peakHistory, peakPairs);
                ConvertPairsToSubFingerprints(peakPairs, subFingerprints);
            }
            FireFingerprintHashesGenerated(track, indices, subFingerprints);

            audioStream.Close();
        }
        /// <summary>
        /// This method generates hash codes from an audio stream in a streaming fashion,
        /// which means that it only maintains a small constant-size state and can process
        /// streams of arbitrary length.
        ///
        /// Here is a scheme of the data processing flow. After the subband splitting
        /// stage, every subband is processed independently.
        /// 
        ///                    +-----------------+   +--------------+   +-----------+
        ///   audio stream +---> mono conversion +---> downsampling +---> whitening |
        ///                    +-----------------+   +--------------+   +---------+-+
        ///                                                                       |
        ///                        +-------------------+   +------------------+   |
        ///                        | subband splitting <---+ subband analysis <---+
        ///                        +--+---+---+---+----+   +------------------+
        ///                           |   |   |   |
        ///                           |   v   v   v
        ///                           |  ... ... ...
        ///                           |
        ///                           |   +------------------+   +-----------------+
        ///                           +---> RMS downsampling +---> onset detection |
        ///                               +------------------+   +----------+------+
        ///                                                                 |
        ///                                    +-----------------+          |
        ///   hash codes   <-------------------+ hash generation <----------+
        ///                                    +-----------------+
        ///
        /// The hash codes from the hash generators of each band are then sent though a
        /// sorter which brings them into sequential temporal order before they are stored
        /// in the final list.
        /// </summary>
        /// <param name="track"></param>
        public void Generate(AudioTrack track)
        {
            IAudioStream audioStream = new ResamplingStream(
                new MonoStream(AudioStreamFactory.FromFileInfoIeee32(track.FileInfo)),
                ResamplingQuality.Medium, profile.SamplingRate);

            var whiteningStream = new WhiteningStream(audioStream,
                                                      profile.WhiteningNumPoles, profile.WhiteningDecaySecs, profile.WhiteningBlockLength);
            var subbandAnalyzer = new SubbandAnalyzer(whiteningStream);

            float[] analyzedFrame = new float[profile.SubBands];

            var bandAnalyzers = new BandAnalyzer[profile.SubBands];

            for (int i = 0; i < profile.SubBands; i++)
            {
                bandAnalyzers[i] = new BandAnalyzer(profile, i);
            }

            List <SubFingerprint> hashes     = new List <SubFingerprint>();
            HashTimeSorter        hashSorter = new HashTimeSorter(profile.SubBands);

            var sw = new Stopwatch();

            sw.Start();

            int totalFrames  = subbandAnalyzer.WindowCount;
            int currentFrame = 0;

            while (subbandAnalyzer.HasNext())
            {
                subbandAnalyzer.ReadFrame(analyzedFrame);

                for (int i = 0; i < profile.SubBands; i++)
                {
                    bandAnalyzers[i].ProcessSample(analyzedFrame[i], hashSorter.Queues[i]);
                }

                if (currentFrame % 4096 == 0)
                {
                    hashSorter.Fill(hashes, false);

                    if (SubFingerprintsGenerated != null)
                    {
                        SubFingerprintsGenerated(this, new SubFingerprintsGeneratedEventArgs(track, hashes, currentFrame, totalFrames));
                        hashes.Clear();
                    }
                }

                currentFrame++;
            }

            for (int i = 0; i < bandAnalyzers.Length; i++)
            {
                bandAnalyzers[i].Flush(hashSorter.Queues[i]);
            }
            hashSorter.Fill(hashes, true);

            if (SubFingerprintsGenerated != null)
            {
                SubFingerprintsGenerated(this, new SubFingerprintsGeneratedEventArgs(track, hashes, currentFrame, totalFrames));
                hashes.Clear();
            }

            sw.Stop();
            audioStream.Close();
            Console.WriteLine("time: " + sw.Elapsed);
        }
Beispiel #17
0
        public float Run()
        {
            IAudioStream audioStream = new ResamplingStream(
                new MonoStream(AudioStreamFactory.FromFileInfoIeee32(audioTrack.FileInfo)),
                ResamplingQuality.Medium, 11000);

            ContinuousFrequencyActivationQuantifier cfaq = new ContinuousFrequencyActivationQuantifier(audioStream);

            float[] cfaValue   = new float[1];
            float[] cfaValues  = new float[cfaq.WindowCount];
            Label[] cfaLabels  = new Label[cfaq.WindowCount];
            int     count      = 0;
            int     musicCount = 0;

            while (cfaq.HasNext())
            {
                cfaq.ReadFrame(cfaValue);
                cfaValues[count] = cfaValue[0];
                if (cfaValue[0] > threshold)
                {
                    musicCount++;
                    cfaLabels[count] = Label.MUSIC;
                }
                Console.WriteLine("cfa {0,3}% {3} {1,5:0.00} {2}", (int)(Math.Round((float)count++ / cfaq.WindowCount * 100)), cfaValue[0], cfaValue[0] > threshold ? "MUSIC" : "", TimeUtil.BytesToTimeSpan(audioStream.Position, audioStream.Properties));
            }

            audioStream.Close();

            if (smoothing)
            {
                // 3.3 Smoothing

                /* majority filtering with sliding window ~5 secs
                 * 1 frame = ~2,4 secs, at least 3 frames are needed for majority filtering -> 3 * ~2,4 secs = ~7,2 secs */

                // filter out single NO_MUSIC frames
                for (int i = 2; i < cfaLabels.Length; i++)
                {
                    if (cfaLabels[i - 2] == Label.MUSIC && cfaLabels[i - 1] == Label.NO_MUSIC && cfaLabels[i] == Label.MUSIC)
                    {
                        cfaLabels[i - 1] = Label.MUSIC;
                    }
                }

                // filter out single MUSIC frames
                for (int i = 2; i < cfaLabels.Length; i++)
                {
                    if (cfaLabels[i - 2] == Label.NO_MUSIC && cfaLabels[i - 1] == Label.MUSIC && cfaLabels[i] == Label.NO_MUSIC)
                    {
                        cfaLabels[i - 1] = Label.NO_MUSIC;
                    }
                }

                // swap ~5 secs NO_MUSIC segments to MUSIC
                for (int i = 3; i < cfaLabels.Length; i++)
                {
                    if (cfaLabels[i - 3] == Label.MUSIC && cfaLabels[i - 2] == Label.NO_MUSIC && cfaLabels[i - 1] == Label.NO_MUSIC && cfaLabels[i] == Label.MUSIC)
                    {
                        cfaLabels[i - 1] = Label.MUSIC;
                        cfaLabels[i - 2] = Label.MUSIC;
                    }
                }

                // swap ~5 secs NMUSIC segments to NO_MUSIC
                for (int i = 3; i < cfaLabels.Length; i++)
                {
                    if (cfaLabels[i - 3] == Label.NO_MUSIC && cfaLabels[i - 2] == Label.MUSIC && cfaLabels[i - 1] == Label.MUSIC && cfaLabels[i] == Label.NO_MUSIC)
                    {
                        cfaLabels[i - 1] = Label.NO_MUSIC;
                        cfaLabels[i - 2] = Label.NO_MUSIC;
                    }
                }
            }

            float musicRatio         = (float)musicCount / count;
            float musicRatioSmoothed = -1f;

            Console.WriteLine("'" + audioTrack.FileInfo.FullName + "' contains " + ((int)(Math.Round(musicRatio * 100))) + "% music");

            if (smoothing)
            {
                musicCount         = cfaLabels.Count <Label>(l => l == Label.MUSIC);
                musicRatioSmoothed = (float)musicCount / count;
                Console.WriteLine("smoothed: " + ((int)(Math.Round(musicRatioSmoothed * 100))) + "% music");
            }

            if (writeLog)
            {
                FileInfo     logFile = new FileInfo(audioTrack.FileInfo.FullName + ".music");
                StreamWriter writer  = logFile.CreateText();

                writer.WriteLine(musicRatio + "; " + musicRatioSmoothed);
                writer.WriteLine(threshold);

                for (int i = 0; i < cfaValues.Length; i++)
                {
                    writer.WriteLine("{0:0.00000}; {1}; \t{2}", cfaValues[i], cfaValues[i] > threshold ? Label.MUSIC : Label.NO_MUSIC, cfaLabels[i]);
                }

                writer.Flush();
                writer.Close();
            }

            return(0);
        }
Beispiel #18
0
        public void Generate(AudioTrack track)
        {
            IAudioStream audioStream = new ResamplingStream(
                new MonoStream(AudioStreamFactory.FromFileInfoIeee32(track.FileInfo)),
                ResamplingQuality.Medium, profile.SamplingRate);

            var chroma = new Chroma(audioStream, profile.WindowSize, profile.HopSize, profile.WindowType,
                                    profile.ChromaMinFrequency, profile.ChromaMaxFrequency, false, profile.ChromaMappingMode);

            float[] chromaFrame;
            var     chromaBuffer             = new RingBuffer <float[]>(profile.ChromaFilterCoefficients.Length);
            var     chromaFilterCoefficients = profile.ChromaFilterCoefficients;
            var     filteredChromaFrame      = new double[Chroma.Bins];
            var     classifiers     = profile.Classifiers;
            var     maxFilterWidth  = classifiers.Max(c => c.Filter.Width);
            var     integralImage   = new IntegralImage(maxFilterWidth, Chroma.Bins);
            int     index           = 0;
            int     indices         = chroma.WindowCount;
            var     subFingerprints = new List <SubFingerprint>();

            while (chroma.HasNext())
            {
                // Get chroma frame buffer
                // When the chroma buffer is full, we can take and reuse the oldest array
                chromaFrame = chromaBuffer.Count == chromaBuffer.Length ? chromaBuffer[0] : new float[Chroma.Bins];

                // Read chroma frame into buffer
                chroma.ReadFrame(chromaFrame);

                // ChromaFilter
                chromaBuffer.Add(chromaFrame);
                if (chromaBuffer.Count < chromaBuffer.Length)
                {
                    // Wait for the buffer to fill completely for the filtering to start
                    continue;
                }
                Array.Clear(filteredChromaFrame, 0, filteredChromaFrame.Length);
                for (int i = 0; i < chromaFilterCoefficients.Length; i++)
                {
                    var frame = chromaBuffer[i];
                    for (int j = 0; j < frame.Length; j++)
                    {
                        filteredChromaFrame[j] += frame[j] * chromaFilterCoefficients[i];
                    }
                }

                // ChromaNormalizer
                double euclideanNorm = 0;
                for (int i = 0; i < filteredChromaFrame.Length; i++)
                {
                    var value = filteredChromaFrame[i];
                    euclideanNorm += value * value;
                }
                euclideanNorm = Math.Sqrt(euclideanNorm);
                if (euclideanNorm < profile.ChromaNormalizationThreshold)
                {
                    Array.Clear(filteredChromaFrame, 0, filteredChromaFrame.Length);
                }
                else
                {
                    for (int i = 0; i < filteredChromaFrame.Length; i++)
                    {
                        filteredChromaFrame[i] /= euclideanNorm;
                    }
                }

                // ImageBuilder
                // ... just add one feature vector after another as rows to the image
                integralImage.AddColumn(filteredChromaFrame);

                // FingerprintCalculator
                if (integralImage.Columns < maxFilterWidth)
                {
                    // Wait for the image to fill completely before hashes can be generated
                    continue;
                }
                // Calculate subfingerprint hash
                uint hash = 0;
                for (int i = 0; i < classifiers.Length; i++)
                {
                    hash = (hash << 2) | grayCodeMapping[classifiers[i].Classify(integralImage, 0)];
                }
                // We have a SubFingerprint@frameTime
                subFingerprints.Add(new SubFingerprint(index, new SubFingerprintHash(hash), false));

                index++;

                if (index % 512 == 0 && SubFingerprintsGenerated != null)
                {
                    SubFingerprintsGenerated(this, new SubFingerprintsGeneratedEventArgs(track, subFingerprints, index, indices));
                    subFingerprints.Clear();
                }
            }

            if (SubFingerprintsGenerated != null)
            {
                SubFingerprintsGenerated(this, new SubFingerprintsGeneratedEventArgs(track, subFingerprints, index, indices));
            }

            if (Completed != null)
            {
                Completed(this, EventArgs.Empty);
            }

            audioStream.Close();
        }
Beispiel #19
0
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("no file(s) specified");
                Console.WriteLine();
                Console.WriteLine("Usage: MusicDetector file_1 file_2 ... file_n");
                Console.WriteLine("");
                Console.WriteLine("This tool expects at least one file, either specified as filename or " +
                                  "filename wildcard pattern. It scans all files for music content and writes " +
                                  "detection results in separate text files named {file_x}.music. Errors are logged " +
                                  "to a seperate error.log text file.");
                return;
            }

            // Use PFFFT as FFT implementation
            FFTFactory.Factory = new Aurio.PFFFT.FFTFactory();
            // Use Soxr as resampler implementation
            ResamplerFactory.Factory = new Aurio.Soxr.ResamplerFactory();
            // Use FFmpeg for file reading/decoding
            AudioStreamFactory.AddFactory(new FFmpegAudioStreamFactory());

            Queue <FileInfo> scanQueue = new Queue <FileInfo>();

            foreach (string file in args)
            {
                if (file.Contains("*"))
                {
                    int slashIndex = file.LastIndexOf(@"\");
                    var di         = new DirectoryInfo(slashIndex > -1 ? file.Substring(0, slashIndex) : ".");
                    foreach (var fi in di.GetFiles(file.Substring(slashIndex > -1 ? slashIndex + 1 : 0), SearchOption.TopDirectoryOnly))
                    {
                        scanQueue.Enqueue(fi);
                    }
                }
                else
                {
                    scanQueue.Enqueue(new FileInfo(file));
                }
            }

            FileInfo     errorLogFileInfo = new FileInfo("error.log");
            StreamWriter errorLogWriter   = errorLogFileInfo.AppendText();

            foreach (var fi in scanQueue)
            {
                try {
                    if (fi.Exists && fi.Length > 0)
                    {
                        new CFA(new AudioTrack(fi), CFA.DEFAULT_THRESHOLD, true, true).Run();
                    }
                    else
                    {
                        throw new FileNotFoundException(String.Format("file '{0}' not existing or empty, skipping", fi.FullName));
                    }
                }
                catch (FileNotFoundException e) {
                    Console.WriteLine(DateTime.Now + " " + e.Message);
                    errorLogWriter.WriteLine(DateTime.Now + " " + e.Message);
                }
                catch (Exception e) {
                    Console.WriteLine(DateTime.Now + " " + e.ToString());
                    Console.WriteLine();

                    errorLogWriter.WriteLine(DateTime.Now + " " + fi.FullName);
                    errorLogWriter.WriteLine(e.ToString());
                }
            }

            errorLogWriter.Flush();
            errorLogWriter.Close();
        }
Beispiel #20
0
        public MainWindow()
        {
            // Use PFFFT as FFT implementation
            FFTFactory.Factory = new Aurio.PFFFT.FFTFactory();
            // Use Soxr as resampler implementation
            ResamplerFactory.Factory = new Aurio.Soxr.ResamplerFactory();
            // Use FFmpeg for file reading/decoding
            AudioStreamFactory.AddFactory(new FFmpegAudioStreamFactory());

            recentProjects = new RecentProjects();

            /*
             * The menu items of the recently opened project are handled here in code behind
             * because in XAML (ItemsSource/CompositeCollection/CollectionViewSource/CollectionContainer)
             * there's a few problems I spent too much time with and could not solve. This
             * programmatic solution works perfectly.
             *
             * - When overriding the ItemContainerStyle, which is necessary to automatically
             *   set the Header and Command, the style breaks... this is probably because of
             *   the weird style combination I'm using in this app and wouldn't happen with
             *   the default style (setting ItemContainerStyle replaces the style in the locally
             *   included style file and falls back to proerties of the default style for the app).
             * - When setting the header text through the style, the header text of all statically
             *   defined MenuItems gets overwritten because they don't have the header directly
             *   set but get the header text from the associated command. So the header text
             *   overrules the command text.
             */
            recentProjects.MenuEntries.CollectionChanged += delegate(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
                // Always rebuilt the whole menu... happens very seldomly and shouldn't be a noticable performance impact
                int separatorIndex = FileMenu.Items.IndexOf(RecentSeparator);

                // Clear old entries
                if (FileMenu.Items.Count > (separatorIndex + 1))
                {
                    for (int x = FileMenu.Items.Count - 1; x > separatorIndex; x--)
                    {
                        FileMenu.Items.RemoveAt(x);
                    }
                }

                Debug.Assert(FileMenu.Items.Count == separatorIndex + 1, "wrong menu delete count");

                // Add new entries
                int count = 0;
                foreach (RecentProjects.RecentEntry entry in recentProjects.MenuEntries)
                {
                    // Determine if this item represents a real project to be numbered
                    bool projectEntry = entry.Parameter != null && entry.Parameter != RecentProjects.ClearCommand;

                    FileMenu.Items.Add(new MenuItem {
                        Header           = (projectEntry ? (++count) + " " : "") + entry.Title.Replace("_", "__"),
                        IsEnabled        = entry.Enabled,
                        Command          = Commands.FileOpenRecentProject,
                        CommandParameter = entry.Parameter
                    });
                }

                Debug.Assert(FileMenu.Items.Count == separatorIndex + 1 + recentProjects.MenuEntries.Count, "wrong menu item count");
            };

            project   = new Project();
            trackList = new TrackList <AudioTrack>();

            InitializeComponent();
            recentProjects.Load();
        }
        /// <summary>
        /// Creates a Wave format proxy file in the same directory and with the same name as the specified file,
        /// if no storage directory is specified (i.e. if it is null). If a storage directory is specified, the proxy
        /// file will be stored in the specified directory with a hashed file name to avoid name collisions and
        /// file overwrites. The story directory option is convenient for the usage of temporary or working directories.
        /// </summary>
        /// <param name="fileInfo">the file for which a proxy file should be created</param>
        /// <param name="storageDirectory">optional directory where the proxy file will be stored, can be null</param>
        /// <returns>the FileInfo of the proxy file</returns>
        public static FileInfo CreateWaveProxy(FileInfo fileInfo, DirectoryInfo storageDirectory)
        {
            FileInfo outputFileInfo;

            if (storageDirectory == null)
            {
                // Without a storage directory, store the proxy file beside the original file
                outputFileInfo = new FileInfo(fileInfo.FullName + ".ffproxy.wav");
            }
            else
            {
                // With a storage directory specified, store the proxy file with a hashed name
                // (to avoid name collision / overwrites) in the target directory (e.g. a temp or working directory)
                using (var sha256 = SHA256.Create()) {
                    byte[] hash       = sha256.ComputeHash(Encoding.Unicode.GetBytes(fileInfo.FullName));
                    string hashString = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
                    outputFileInfo = new FileInfo(Path.Combine(storageDirectory.FullName, hashString + ".ffproxy.wav"));
                }
            }


            if (outputFileInfo.Exists)
            {
                Console.WriteLine("Proxy already existing, using " + outputFileInfo.Name);
                return(outputFileInfo);
            }

            var reader = new FFmpegReader(fileInfo, FFmpeg.Type.Audio);

            var writer = new MemoryWriterStream(new AudioProperties(
                                                    reader.AudioOutputConfig.format.channels,
                                                    reader.AudioOutputConfig.format.sample_rate,
                                                    reader.AudioOutputConfig.format.sample_size * 8,
                                                    reader.AudioOutputConfig.format.sample_size == 4 ? AudioFormat.IEEE : AudioFormat.LPCM));

            int output_buffer_size = reader.AudioOutputConfig.frame_size * writer.SampleBlockSize;

            byte[] output_buffer = new byte[output_buffer_size];

            int  samplesRead;
            long timestamp;

            FFmpeg.Type type;

            // sequentially read samples from decoder and write it to wav file
            while ((samplesRead = reader.ReadFrame(out timestamp, output_buffer, output_buffer_size, out type)) > 0)
            {
                int bytesRead = samplesRead * writer.SampleBlockSize;
                writer.Write(output_buffer, 0, bytesRead);
            }

            reader.Dispose();

            writer.Position = 0;

            AudioStreamFactory.WriteToFile(writer, outputFileInfo.FullName);

            writer.Close();

            return(outputFileInfo);
        }