public virtual long GetLength(EncoderItem encoderItem, IBassStream stream) { var source = default(int); var channelInfo = default(ChannelInfo); var inputLength = stream.Length; if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } if (channelInfo.Flags.HasFlag(BassFlags.Float)) { source = DEPTH_32; } else { source = DEPTH_16; } var outputLength = (long)(inputLength / (source / (float)this.GetDepth(encoderItem, stream))); if (inputLength != outputLength) { Logger.Write(this, LogLevel.Debug, "Conversion requires change of data length: {0} bytes => {1} bytes.", inputLength, outputLength); } return(outputLength); }
public override string GetArguments(EncoderItem encoderItem, IBassStream stream) { var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } var depth = this.Settings.GetDepth(encoderItem, stream); if (channelInfo.Flags.HasFlag(BassFlags.Float)) { Logger.Write(this.GetType(), LogLevel.Debug, "Resampling file \"{0}\" from 32 bit float to {1} bit integer.", encoderItem.InputFileName, depth); return(string.Format( "-t raw -e floating-point --bits 32 -r {0} -c {1} - -t raw -e signed-integer --bits {2} -r {0} -c {1} -", channelInfo.Frequency, channelInfo.Channels, depth )); } else { Logger.Write(this.GetType(), LogLevel.Debug, "Resampling file \"{0}\" from 16 bit integer to {1} bit integer.", encoderItem.InputFileName, depth); return(string.Format( "-t raw -e signed-integer --bits 16 -r {0} -c {1} - -t raw -e signed-integer --bits {2} -r {0} -c {1} -", channelInfo.Frequency, channelInfo.Channels, depth )); } }
public static EncoderItem Create(string inputFileName, string outputFileName, IList <MetaDataItem> metaDatas, string profile) { var encoderItem = new EncoderItem() { InputFileName = inputFileName, OutputFileName = outputFileName, Profile = profile }; if (metaDatas != null) { var metaData = default(IDictionary <string, string>); lock (metaDatas) { metaData = metaDatas.ToDictionary( metaDataItem => metaDataItem.Name, metaDataItem => metaDataItem.Value, StringComparer.OrdinalIgnoreCase ); } encoderItem.Bitrate = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioBitrate)); encoderItem.Channels = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioChannels)); encoderItem.SampleRate = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioSampleRate)); encoderItem.BitsPerSample = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.BitsPerSample)); } return(encoderItem); }
protected virtual void EncodeWithResampler(EncoderItem encoderItem, IBassStream stream, IBassEncoderSettings settings) { using (var resamplerProcess = this.CreateResamplerProcess(encoderItem, stream, new SoxEncoderSettings(settings))) { using (var encoderProcess = this.CreateEncoderProcess(encoderItem, stream, settings)) { var success = true; this.EncodeWithResampler(encoderItem, stream, resamplerProcess, encoderProcess); if (this.WaitForExit(resamplerProcess)) { if (resamplerProcess.ExitCode != 0) { success = false; } } if (this.WaitForExit(encoderProcess)) { if (encoderProcess.ExitCode != 0) { success = false; } } if (!success) { throw new InvalidOperationException("Process does not indicate success."); } } } }
public virtual int GetDepth(EncoderItem encoderItem, IBassStream stream) { if (this.Format.AutoDepth) { switch (encoderItem.BitsPerSample) { case DEPTH_16: case DEPTH_24: case DEPTH_32: Logger.Write(this, LogLevel.Debug, "Using meta data suggested bit depth for file \"{0}\": {1} bit", encoderItem.InputFileName, encoderItem.BitsPerSample); return(encoderItem.BitsPerSample); } var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } if (channelInfo.Flags.HasFlag(BassFlags.Float)) { Logger.Write(this, LogLevel.Debug, "Using decoder bit depth for file \"{0}\": 32 bit", encoderItem.InputFileName); return(DEPTH_32); } else { Logger.Write(this, LogLevel.Debug, "Using decoder bit depth for file \"{0}\": 16 bit", encoderItem.InputFileName); return(DEPTH_16); } } Logger.Write(this, LogLevel.Debug, "Using user defined bit depth for file \"{0}\": {1} bit", encoderItem.InputFileName, this.Format.Depth); return(this.Format.Depth); }
public override string GetArguments(EncoderItem encoderItem, IBassStream stream) { var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } var length = this.GetLength(encoderItem, stream); var arguments = string.Format( "--no-seektable --force-raw-format --endian=little --sign=signed --sample-rate={0} --channels={1} --bps={2} - --compression-level-{3} -o \"{4}\"", channelInfo.Frequency, channelInfo.Channels, this.GetDepth(encoderItem, stream), this.Compression, encoderItem.OutputFileName ); if (this.IgnoreErrors) { arguments += " --decode-through-errors"; } else { arguments += string.Format( "--input-size={0}", length ); } return(arguments); }
protected virtual Action <Exception> GetErrorHandler(EncoderItem encoderItem) { return(e => { Logger.Write(this, LogLevel.Warn, "Encoder background thread for file \"{0}\" error: {1}", encoderItem.InputFileName, e.Message); encoderItem.AddError(e.Message); }); }
protected virtual void OnStatusChanged(EncoderItem encoderItem) { if (this.StatusChanged == null) { return; } this.StatusChanged(this, new BassEncoderMonitorEventArgs(encoderItem)); }
public EncodePlaylistItemsTask(BassEncoderBehaviour behaviour, PlaylistItem[] playlistItems) : this() { this.Behaviour = behaviour; this.PlaylistItems = playlistItems; this.EncoderItems = playlistItems .OrderBy(playlistItem => playlistItem.FileName) .Select(playlistItem => EncoderItem.FromPlaylistItem(playlistItem)) .ToArray(); }
protected virtual void UpdateStatus(EncoderItem encoderItem) { var currentEncoderItem = default(EncoderItem); if (this.EncoderItems.TryGetValue(encoderItem.Id, out currentEncoderItem) && currentEncoderItem.Status != encoderItem.Status) { Logger.Write(this, LogLevel.Debug, "Encoder status changed for file \"{0}\": {1}", encoderItem.InputFileName, Enum.GetName(typeof(EncoderItemStatus), encoderItem.Status)); this.OnStatusChanged(encoderItem); } this.EncoderItems[encoderItem.Id] = encoderItem; }
public override string GetArguments(EncoderItem encoderItem, IBassStream stream) { return(string.Format( "-i -q -y --raw-pcm={0} {1} -x{2} {3} - \"{4}\"", this.GetFormat(encoderItem, stream), this.GetCompression(), this.Processing, this.GetHybrid(), encoderItem.OutputFileName )); }
protected virtual void Encode(EncoderItem encoderItem, IBassEncoderSettings settings) { var flags = BassFlags.Decode; if (this.ShouldDecodeFloat(encoderItem, settings)) { Logger.Write(this, LogLevel.Debug, "Decoding file \"{0}\" in high quality mode (32 bit floating point).", encoderItem.InputFileName); flags |= BassFlags.Float; } else { Logger.Write(this, LogLevel.Debug, "Decoding file \"{0}\" in standaed quality mode (16 bit integer).", encoderItem.InputFileName); } var stream = this.CreateStream(encoderItem.InputFileName, flags); if (stream.IsEmpty) { Logger.Write(this, LogLevel.Debug, "Failed to create stream for file \"{0}\": Unknown error.", encoderItem.InputFileName); return; } Logger.Write(this, LogLevel.Debug, "Created stream for file \"{0}\": {1}", encoderItem.InputFileName, stream.ChannelHandle); try { if (flags.HasFlag(BassFlags.Float)) { this.EncodeWithResampler(encoderItem, stream, settings); } else { this.Encode(encoderItem, stream, settings); } } finally { Logger.Write(this, LogLevel.Debug, "Releasing stream for file \"{0}\": {1}", encoderItem.InputFileName, 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) { encoderItem.Status = EncoderItemStatus.Cancelled; if (File.Exists(encoderItem.OutputFileName)) { Logger.Write(this, LogLevel.Debug, "Deleting incomplete output \"{0}\": Cancelled.", encoderItem.OutputFileName); File.Delete(encoderItem.OutputFileName); } } else { encoderItem.Status = EncoderItemStatus.Complete; } }
protected virtual void Encode(EncoderItem encoderItem, IBassStream stream, IBassEncoderSettings settings) { using (var encoderProcess = this.CreateEncoderProcess(encoderItem, stream, settings)) { this.Encode(encoderItem, stream, encoderProcess); if (this.WaitForExit(encoderProcess)) { if (encoderProcess.ExitCode != 0) { throw new InvalidOperationException("Process does not indicate success."); } } } }
protected virtual string GetFormat(EncoderItem encoderItem, IBassStream stream) { var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } return(string.Format( "{0},{1}s,{2},le", channelInfo.Frequency, this.GetDepth(encoderItem, stream), channelInfo.Channels )); }
protected virtual bool ShouldDecodeFloat(EncoderItem encoderItem, IBassEncoderSettings settings) { if (encoderItem.BitsPerSample == 1) { Logger.Write(this, LogLevel.Debug, "Suggesting high quality mode for file \"{0}\": dsd.", encoderItem.InputFileName); return(true); } if (encoderItem.BitsPerSample > 16 || settings.Format.Depth > 16) { Logger.Write(this, LogLevel.Debug, "Suggesting high quality mode for file \"{0}\": >16 bit.", encoderItem.InputFileName); return(true); } Logger.Write(this, LogLevel.Debug, "Suggesting standard quality mode for file \"{0}\": <=16 bit.", encoderItem.InputFileName); return(false); }
protected virtual string GetDescription(EncoderItem encoderItem) { var builder = new StringBuilder(); builder.AppendFormat("{0} -> {1}", encoderItem.InputFileName, encoderItem.OutputFileName); if (encoderItem.Status != EncoderItemStatus.Complete && encoderItem.Errors.Any()) { builder.Append(Environment.NewLine); foreach (var error in encoderItem.Errors) { builder.Append("\t"); builder.Append(error); } } return(builder.ToString()); }
public override int GetDepth(EncoderItem encoderItem, IBassStream stream) { var depth = base.GetDepth(encoderItem, stream); if (depth < DEPTH_16) { Logger.Write(this.GetType(), LogLevel.Warn, "Requsted bit depth {0} is invalid, using minimum: 16 bit", depth); return(DEPTH_16); } if (depth > DEPTH_32) { Logger.Write(this.GetType(), LogLevel.Warn, "Requsted bit depth {0} is invalid, using maximum: 32 bit", depth); return(DEPTH_32); } return(depth); }
public static EncoderItem FromPlaylistItem(PlaylistItem playlistItem) { var encoderItem = new EncoderItem() { InputFileName = playlistItem.FileName }; if (playlistItem.MetaDatas != null) { var metaData = playlistItem.MetaDatas.ToDictionary(metaDataItem => metaDataItem.Name, metaDataItem => metaDataItem.Value, StringComparer.OrdinalIgnoreCase); encoderItem.Bitrate = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioBitrate)); encoderItem.Channels = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioChannels)); encoderItem.SampleRate = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioSampleRate)); encoderItem.BitsPerSample = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.BitsPerSample)); } return(encoderItem); }
public override string GetArguments(EncoderItem encoderItem, IBassStream stream) { var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } return(string.Format( "--alac --raw --raw-rate {0} --raw-channels {1} --raw-format {2} - --bits-per-sample {3} -o \"{4}\"", channelInfo.Frequency, channelInfo.Channels, this.GetFormat(encoderItem, stream), this.GetDepth(encoderItem, stream), encoderItem.OutputFileName )); }
public override string GetArguments(EncoderItem encoderItem, IBassStream stream) { var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } return(string.Format( "--quiet --raw --raw-rate={0} --raw-chan={1} --raw-bits={2} --raw-endianness=0 - --quality={3} -o \"{4}\"", channelInfo.Frequency, channelInfo.Channels, this.GetDepth(encoderItem, stream), this.Quality, encoderItem.OutputFileName )); }
public override string GetArguments(EncoderItem encoderItem, IBassStream stream) { var channelInfo = default(ChannelInfo); if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo)) { throw new NotImplementedException(); } return(string.Format( "--silent -r --little-endian --signed -s {0} -m {1} --bitwidth {2} - --cbr -b {3} \"{4}\"", channelInfo.Frequency, this.GetStereoMode(channelInfo.Channels), this.GetDepth(encoderItem, stream), this.Bitrate, encoderItem.OutputFileName )); }
protected virtual Process CreateEncoderProcess(EncoderItem encoderItem, IBassStream stream, IBassEncoderSettings settings) { Logger.Write(this, LogLevel.Debug, "Creating encoder process for file \"{0}\".", encoderItem.InputFileName); var arguments = settings.GetArguments(encoderItem, stream); var process = this.CreateProcess( encoderItem, stream, settings.Executable, settings.Directory, arguments, true, false, true ); Logger.Write(this, LogLevel.Debug, "Created encoder process for file \"{0}\": \"{1}\" {2}", encoderItem.InputFileName, settings.Executable, arguments); return(process); }
protected virtual async Task CopyTags(EncoderItem encoderItem) { try { Logger.Write(this, LogLevel.Debug, "Copying tags from \"{0}\" to \"{1}\".", encoderItem.InputFileName, encoderItem.OutputFileName); var fileData = this.GetFileData(encoderItem); using (var task = new WriteFileMetaDataTask(encoderItem.OutputFileName, fileData.MetaDatas)) { task.InitializeComponent(this.Core); await task.Run().ConfigureAwait(false); } } catch (Exception e) { Logger.Write(this, LogLevel.Warn, "Failed to copy tags from \"{0}\" to \"{1}\": {2}", encoderItem.InputFileName, encoderItem.OutputFileName, e.Message); await this.OnError(e).ConfigureAwait(false); } }
protected virtual void Encode(EncoderItem encoderItem, IBassStream stream, Process encoderProcess) { var channelReader = new ChannelReader(encoderItem, stream); var encoderWriter = new ProcessWriter(encoderProcess); var thread = new Thread(() => { this.Try(() => channelReader.CopyTo(encoderWriter, this.CancellationToken), this.GetErrorHandler(encoderItem)); }) { Name = string.Format("ChannelReader(\"{0}\", {1})", encoderItem.InputFileName, stream.ChannelHandle), IsBackground = true }; Logger.Write(this, LogLevel.Debug, "Starting background thread for file \"{0}\".", encoderItem.InputFileName); thread.Start(); Logger.Write(this, LogLevel.Debug, "Completing background thread for file \"{0}\".", encoderItem.InputFileName); this.Join(thread); encoderWriter.Close(); }
protected virtual Process CreateProcess(EncoderItem encoderItem, IBassStream stream, string executable, string directory, string arguments, bool redirectStandardInput, bool redirectStandardOutput, bool redirectStandardError) { if (!File.Exists(executable)) { throw new InvalidOperationException(string.Format("A required utility was not found: {0}", executable)); } var processStartInfo = new ProcessStartInfo() { FileName = executable, WorkingDirectory = directory, Arguments = arguments, RedirectStandardInput = redirectStandardInput, RedirectStandardOutput = redirectStandardOutput, RedirectStandardError = redirectStandardError, UseShellExecute = false, CreateNoWindow = true }; var process = Process.Start(processStartInfo); try { process.PriorityClass = ProcessPriorityClass.BelowNormal; } catch { //Nothing can be done, probably access denied. } process.ErrorDataReceived += (sender, e) => { if (string.IsNullOrEmpty(e.Data)) { return; } Logger.Write(this, LogLevel.Trace, "{0}: {1}", executable, e.Data); encoderItem.AddError(e.Data); }; process.BeginErrorReadLine(); return(process); }
public BassEncoderMonitorEventArgs(EncoderItem encoderItem) { this.EncoderItem = encoderItem; }
public override int GetDepth(EncoderItem encoderItem, IBassStream stream) { return(DEPTH_16); }
protected virtual IFileData GetFileData(EncoderItem encoderItem) { return(this.FileDatas.FirstOrDefault(fileData => string.Equals(fileData.FileName, encoderItem.InputFileName, StringComparison.OrdinalIgnoreCase))); }
public EncoderItem Create(IFileData[] fileDatas, IFileData fileData, string profile) { var outputFileName = this.GetOutputFileName(fileDatas, fileData, profile); return(EncoderItem.Create(fileData.FileName, outputFileName, fileData.MetaDatas, profile)); }
public ReportRow(Guid id, EncoderItem encoderItem) { this.Id = id; this.EncoderItem = encoderItem; }