protected virtual void ScanTrack(ScannerItem scannerItem)
        {
            var success = default(bool);
            var flags   = BassFlags.Decode | BassFlags.Float;
            var stream  = this.CreateStream(scannerItem.FileName, flags);

            if (stream.IsEmpty)
            {
                Logger.Write(this, LogLevel.Warn, "Failed to create stream for file \"{0}\": Unknown error.", scannerItem.FileName);
                throw new InvalidOperationException(string.Format("Failed to create stream for file \"{0}\": Unknown error.", scannerItem.FileName));
            }
            Logger.Write(this, LogLevel.Debug, "Created stream for file \"{0}\": {1}", scannerItem.FileName, stream.ChannelHandle);
            var monitor = new ChannelMonitor(scannerItem, stream);

            try
            {
                monitor.Start();
                success = this.ScanTrack(scannerItem, stream);
            }
            finally
            {
                monitor.Dispose();
                Logger.Write(this, LogLevel.Debug, "Releasing stream for file \"{0}\": {1}", scannerItem.FileName, stream.ChannelHandle);
                Bass.StreamFree(stream.ChannelHandle); //Not checking result code as it contains an error if the application is shutting down.
            }
            if (this.CancellationToken.IsCancellationRequested)
            {
                scannerItem.Status = ScannerItemStatus.Cancelled;
            }
            else if (success)
            {
                scannerItem.Status = ScannerItemStatus.Complete;
            }
            else
            {
                Logger.Write(this, LogLevel.Warn, "Scanning file \"{0}\" failed: The format is likely not supported.", scannerItem.FileName);
                scannerItem.AddError("The format is likely not supported.");
                scannerItem.Status = ScannerItemStatus.Failed;
            }
        }
        protected virtual void ScanGroups(IEnumerable <IEnumerable <ScannerItem> > groups)
        {
            var parallelOptions = new ParallelOptions()
            {
                MaxDegreeOfParallelism = this.Threads
            };

            Parallel.ForEach(groups, parallelOptions, group =>
            {
                var streams = new Dictionary <ScannerItem, IBassStream>();
                foreach (var scannerItem in group)
                {
                    try
                    {
                        if (this.CancellationToken.IsCancellationRequested)
                        {
                            Logger.Write(this, LogLevel.Warn, "Skipping file \"{0}\" due to cancellation.", scannerItem.FileName);
                            scannerItem.Status = ScannerItemStatus.Cancelled;
                            continue;
                        }
                        if (!this.CheckInput(scannerItem.FileName))
                        {
                            Logger.Write(this, LogLevel.Warn, "Skipping file \"{0}\" due to file \"{1}\" does not exist.", scannerItem.FileName);
                            scannerItem.Status = ScannerItemStatus.Failed;
                            scannerItem.AddError(string.Format("File \"{0}\" does not exist.", scannerItem.FileName));
                            continue;
                        }
                        var flags  = BassFlags.Decode | BassFlags.Float;
                        var stream = this.CreateStream(scannerItem.FileName, flags);
                        if (stream.IsEmpty)
                        {
                            Logger.Write(this, LogLevel.Warn, "Failed to create stream for file \"{0}\": Unknown error.", scannerItem.FileName);
                            throw new InvalidOperationException(string.Format("Failed to create stream for file \"{0}\": Unknown error.", scannerItem.FileName));
                        }
                        Logger.Write(this, LogLevel.Debug, "Created stream for file \"{0}\": {1}", scannerItem.FileName, stream.ChannelHandle);
                        streams.Add(scannerItem, stream);
                        Logger.Write(this, LogLevel.Debug, "Beginning scanning file \"{0}\".", scannerItem.FileName);
                        scannerItem.Progress = ScannerItem.PROGRESS_NONE;
                        scannerItem.Status   = ScannerItemStatus.Processing;
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.Write(this, LogLevel.Warn, "Skipping file \"{0}\" due to cancellation.", scannerItem.FileName);
                        scannerItem.Status = ScannerItemStatus.Cancelled;
                    }
                    catch (Exception e)
                    {
                        Logger.Write(this, LogLevel.Warn, "Scanning file \"{0}\" failed: {1}", scannerItem.FileName, e.Message);
                        scannerItem.Status = ScannerItemStatus.Failed;
                        scannerItem.AddError(e.Message);
                    }
                }
                var success  = default(bool);
                var monitors = new List <ChannelMonitor>();
                try
                {
                    foreach (var scannerItem in streams.Keys)
                    {
                        var stream  = streams[scannerItem];
                        var monitor = new ChannelMonitor(scannerItem, stream);
                        monitor.Start();
                        monitors.Add(monitor);
                    }
                    success = this.ScanGroup(streams);
                }
                finally
                {
                    foreach (var monitor in monitors)
                    {
                        monitor.Dispose();
                    }
                    foreach (var scannerItem in streams.Keys)
                    {
                        var stream = streams[scannerItem];
                        Logger.Write(this, LogLevel.Debug, "Releasing stream for file \"{0}\": {1}", scannerItem.FileName, stream.ChannelHandle);
                        Bass.StreamFree(stream.ChannelHandle); //Not checking result code as it contains an error if the application is shutting down.
                    }
                }
                foreach (var scannerItem in streams.Keys)
                {
                    if (this.CancellationToken.IsCancellationRequested)
                    {
                        scannerItem.Status = ScannerItemStatus.Cancelled;
                    }
                    else if (success)
                    {
                        Logger.Write(this, LogLevel.Debug, "Scanning file \"{0}\" completed successfully.", scannerItem.FileName);
                        scannerItem.Status = ScannerItemStatus.Complete;
                    }
                    else
                    {
                        Logger.Write(this, LogLevel.Warn, "Scanning file \"{0}\" failed: The format is likely not supported.", scannerItem.FileName);
                        scannerItem.AddError("The format is likely not supported.");
                        scannerItem.Status = ScannerItemStatus.Failed;
                    }
                }
            });
        }