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 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 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 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) { 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 bool ScanTrack(ScannerItem scannerItem, IBassStream stream) { var info = default(ReplayGainInfo); if (!BassReplayGain.Process(stream.ChannelHandle, out info)) { return(false); } scannerItem.ItemPeak = info.peak; scannerItem.ItemGain = info.gain; return(true); }
protected virtual long GetLeadOut(IBassStream stream, int threshold) { Logger.Write(this, LogLevel.Debug, "Attempting to calculate lead out for channel {0} with window of {1} seconds and threshold of {2}dB.", stream.ChannelHandle, WINDOW, threshold); var length = Bass.ChannelSeconds2Bytes( stream.ChannelHandle, WINDOW ); if (!this.TrySetPosition(stream, stream.Length - (length * 2))) { Logger.Write(this, LogLevel.Warn, "Failed to synchronize channel {0}, bad plugin? This is very expensive!", stream.ChannelHandle); //Track won't synchronize. MOD files seem to have this problem. return(-1); } do { var levels = new float[1]; if (!Bass.ChannelGetLevel(stream.ChannelHandle, levels, WINDOW, LevelRetrievalFlags.Mono | LevelRetrievalFlags.RMS)) { Logger.Write(this, LogLevel.Warn, "Failed to get levels for channel {0}: {1}", stream.ChannelHandle, Enum.GetName(typeof(Errors), Bass.LastError)); break; } var dB = levels[0] > 0 ? 20 * Math.Log10(levels[0]) : -1000; if (dB > threshold) { //TODO: Sometimes this value is less than zero so clamp it. //TODO: Some problem with BASS/ManagedBass, if you have exactly N bytes available call Bass.ChannelGetLevel with Length = Bass.ChannelBytesToSeconds(N) sometimes results in Errors.Ended. //TODO: Nuts. var leadOut = Math.Max(stream.Length - stream.Position - length, 0); if (leadOut > 0) { Logger.Write(this, LogLevel.Debug, "Successfully calculated lead out for channel {0}: {1} bytes.", stream.ChannelHandle, leadOut); } else { Logger.Write(this, LogLevel.Debug, "Successfully calculated lead out for channel {0}: None.", stream.ChannelHandle); } return(leadOut); } if (!this.TrySetPosition(stream, stream.Position - (length * 2))) { break; } } while (true); //Track was silent? return(-1); }
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 )); }
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 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 )); }
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 )); }
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 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 BassOutputStream(IBassOutput output, IBassStreamPipelineManager manager, IBassStream stream, PlaylistItem playlistItem) : base(playlistItem) { this.Output = output; this.Manager = manager; this.Stream = stream; if (!BassOutputStreams.Add(this)) { //TODO: Warn. } }
protected virtual string GetFormat(EncoderItem encoderItem, IBassStream stream) { return(string.Format("S{0}L", this.GetDepth(encoderItem, stream))); }
protected virtual bool TrySetPosition(IBassStream stream, long position) { return((stream.Position = position) == position); }
public abstract string GetArguments(EncoderItem encoderItem, IBassStream stream);
public ChannelReader(EncoderItem encoderItem, IBassStream stream) { this.EncoderItem = encoderItem; this.Stream = stream; }
public override int GetDepth(EncoderItem encoderItem, IBassStream stream) { return(DEPTH_16); }
public override bool Wrap(IBassStreamProvider provider, int channelHandle, IEnumerable <IBassStreamAdvice> advice, BassFlags flags, out IBassStream stream) { var offset = default(long); var length = default(long); if (this.Offset != TimeSpan.Zero) { offset = Bass.ChannelSeconds2Bytes(channelHandle, this.Offset.TotalSeconds); } if (this.Length != TimeSpan.Zero) { length = Bass.ChannelSeconds2Bytes(channelHandle, this.Length.TotalSeconds); } if (offset != 0 || length != 0) { if (length == 0) { length = Bass.ChannelGetLength(channelHandle, PositionFlags.Bytes) - offset; } stream = new BassStream( provider, BassSubstream.CreateStream(channelHandle, offset, length, flags), length, advice, flags ); return(true); } stream = null; return(false); }
public BassOutputStream(IBassOutput output, IBassStreamPipelineManager manager, IBassStream stream, PlaylistItem playlistItem) : base(playlistItem) { this.Output = output; this.Manager = manager; this.Stream = stream; }
public abstract bool Wrap(IBassStreamProvider provider, int channelHandle, IEnumerable <IBassStreamAdvice> advice, BassFlags flags, out IBassStream stream);
public ChannelMonitor(ScannerItem scannerItem, IBassStream stream) { this.ScannerItem = scannerItem; this.Stream = stream; }