public void Initialize(Stream stream, AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { _stream = stream; InitializeReplayGainFilter(info, metadata, settings); // Call the external ID3 encoder, if available var metadataEncoderFactory = ExtensionProvider.GetFactories <IAudioMetadataEncoder>("Extension", FileExtension).FirstOrDefault(); if (metadataEncoderFactory != null) { using (var export = metadataEncoderFactory.CreateExport()) using (var tempStream = new MemoryStream()) { // Buffer the tag in memory export.Value.WriteMetadata(tempStream, metadata, settings); // Pre-allocate the whole stream (estimate worst case of 320kbps, plus the tag) stream.SetLength(0xA000 * (long)info.PlayLength.TotalSeconds + tempStream.Length); // Flush the tag to the output stream tempStream.WriteTo(stream); } } _encoder = new(stream); _encoder.SetChannels(info.Channels); _encoder.SetSampleRate(info.SampleRate); if (info.FrameCount > 0) { _encoder.SetSampleCount((uint)info.FrameCount); } if (settings.TryGetValue("BitRate", out int bitRate)) { // Use ABR, unless ForceCBR is set to true if (settings.TryGetValue("ForceCBR", out bool forceCbr) && forceCbr) { _encoder.SetBitRate(bitRate); } else { _encoder.SetVbrMeanBitRate(bitRate); _encoder.SetVbrMode(VbrMode.Abr); } } else { // Use VBR quality 3 if nothing else is specified _encoder.SetVbrQuality( settings.TryGetValue("VBRQuality", out int vbrQuality) ? vbrQuality : 3); _encoder.SetVbrMode(VbrMode.Mtrh); } _encoder.InitializeParameters(); }
public void Initialize(Stream stream, AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { InitializeReplayGainFilter(info, metadata, settings); _oggStream = new OggStream(settings.TryGetValue("SerialNumber", out int serialNumber) ? serialNumber : new Random().Next()); // Default to a quality setting of 5 if (settings.TryGetValue("BitRate", out int bitRate)) { if (settings.TryGetValue("ForceCBR", out bool cbr) && cbr) { _encoder = new VorbisEncoder(info.Channels, info.SampleRate, bitRate * 1000, bitRate * 1000, bitRate * 1000); } else { _encoder = new VorbisEncoder(info.Channels, info.SampleRate, -1, bitRate * 1000, -1); } } else { _encoder = new VorbisEncoder(info.Channels, info.SampleRate, settings.TryGetValue("Quality", out int quality) ? quality / 10f : 0.5f); } // Generate the header using (var comment = new MetadataToVorbisCommentAdapter(metadata)) { comment.HeaderOut(_encoder.DspState, out var first, out var second, out var third); _oggStream.PacketIn(first); _oggStream.PacketIn(second); _oggStream.PacketIn(third); } // Buffer the header in memory using (var tempStream = new MemoryStream()) { _outputStream = tempStream; // ReSharper disable once PossibleNullReferenceException while (_oggStream.Flush(out var page)) { WritePage(page); } // Pre-allocate the whole stream (estimate worst case of 500kbps, plus the header) stream.SetLength(0xFA00 * (long)info.PlayLength.TotalSeconds + tempStream.Length); // Flush the headers to the output stream tempStream.WriteTo(stream); } _outputStream = stream; }
public void Initialize(Stream stream, AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { _stream = stream; _metadata = metadata; _settings = settings; InitializeReplayGainFilter(info, metadata, settings); var inputDescription = GetInputDescription(info); _audioFile = new(GetOutputDescription(inputDescription), AudioFileType.M4A, stream); _audioFile.SetProperty(ExtendedAudioFilePropertyId.ClientDataFormat, inputDescription); var converter = _audioFile.GetProperty <IntPtr>(ExtendedAudioFilePropertyId.AudioConverter); var logger = LoggerManager.LoggerFactory.CreateLogger <AacAudioEncoder>(); // Enable high quality (defaults to medium, 0x40) SetConverterProperty(converter, AudioConverterPropertyId.CodecQuality, 0x60); if (settings.TryGetValue("BitRate", out int bitRate)) { switch (bitRate) { case > 256 when info.Channels == 1: logger.LogWarning("The maximum bitrate for 1-channel audio is 256 kbps."); bitRate = 256; break; case < 64 when info.Channels == 2: logger.LogWarning("The minimum bitrate for 2-channel audio is 64 kbps."); bitRate = 64; break; } SetConverterProperty(converter, AudioConverterPropertyId.BitRate, bitRate * 1000); // Set the control mode (constrained is the default) var controlMode = BitrateControlMode.VariableConstrained; if (settings.TryGetValue("ControlMode", out string?controlModeValue)) { if (controlModeValue !.Equals("Average", StringComparison.OrdinalIgnoreCase)) { controlMode = BitrateControlMode.LongTermAverage; } else if (controlModeValue.Equals("Constant", StringComparison.OrdinalIgnoreCase)) { controlMode = BitrateControlMode.Constant; } } SetConverterProperty(converter, AudioConverterPropertyId.BitRateControlMode, (uint)controlMode); }
public void Initialize(AudioInfo info, SettingDictionary settings, GroupToken groupToken) { _analyzer = new R128Analyzer((uint)info.Channels, (uint)info.SampleRate, settings.TryGetValue("PeakAnalysis", out string peakAnalysis) && peakAnalysis.Equals("Interpolated", StringComparison.Ordinal)); _groupState = (GroupState)groupToken.GetOrSetGroupState(new GroupState()); // ReSharper disable once PossibleNullReferenceException _groupState.Handles.Enqueue(_analyzer.Handle); }
public void Initialize(AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { if (settings.TryGetValue("ApplyGain", out string applyGain)) { _scale = applyGain.Equals("Track", StringComparison.OrdinalIgnoreCase) ? CalculateScale(metadata.TrackGain, metadata.TrackPeak) : CalculateScale(metadata.AlbumGain, metadata.AlbumPeak); } // Adjust the metadata so that it remains valid metadata.TrackPeak = CalculatePeak(metadata.TrackPeak, _scale); metadata.AlbumPeak = CalculatePeak(metadata.AlbumPeak, _scale); metadata.TrackGain = CalculateGain(metadata.TrackGain, _scale); metadata.AlbumGain = CalculateGain(metadata.AlbumGain, _scale); }
public void Initialize(Stream stream, AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { InitializeReplayGainFilter(info, metadata, settings); if (!settings.TryGetValue("SerialNumber", out int serialNumber)) #if NETSTANDARD2_0 { using (var random = RandomNumberGenerator.Create()) { var buffer = new byte[sizeof(int)]; random.GetNonZeroBytes(buffer); serialNumber = BitConverter.ToInt32(buffer, 0); } } #else { serialNumber = RandomNumberGenerator.GetInt32(int.MaxValue); } #endif _oggStream = new(serialNumber); // Default to a quality setting of 5 if (settings.TryGetValue("BitRate", out int bitRate)) { if (settings.TryGetValue("ForceCBR", out bool cbr) && cbr) { _encoder = new(info.Channels, info.SampleRate, bitRate * 1000, bitRate * 1000, bitRate * 1000); } else { _encoder = new(info.Channels, info.SampleRate, -1, bitRate * 1000, -1); } } else { _encoder = new(info.Channels, info.SampleRate, settings.TryGetValue("Quality", out int quality) ? quality / 10f : 0.5f); } // Generate the header using (var comment = new MetadataToVorbisCommentAdapter(metadata)) { comment.HeaderOut(_encoder.DspState, out var first, out var second, out var third); _oggStream.PacketIn(first); _oggStream.PacketIn(second); _oggStream.PacketIn(third); } // Buffer the header in memory using (var tempStream = new MemoryStream()) { _outputStream = tempStream; while (_oggStream.Flush(out var page)) { WritePage(page); } // Pre-allocate the whole stream (estimate worst case of 500kbps, plus the header) stream.SetLength(0xFA00 * (long)info.PlayLength.TotalSeconds + tempStream.Length); // Flush the headers to the output stream tempStream.WriteTo(stream); } _outputStream = stream; }
public void Initialize(Stream stream, AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { var gain = 0; if (settings.TryGetValue("ApplyGain", out string applyGain)) { var scale = applyGain.Equals("Track", StringComparison.OrdinalIgnoreCase) ? CalculateScale(metadata.TrackGain, metadata.TrackPeak) : CalculateScale(metadata.AlbumGain, metadata.AlbumPeak); // Adjust the metadata so that it remains valid metadata.TrackGain = CalculateGain(metadata.TrackGain, scale); metadata.AlbumGain = CalculateGain(metadata.AlbumGain, scale); gain = (int)Math.Round(Math.Log10(scale) * 5120); } _comments = new MetadataToOpusCommentAdapter(metadata); _encoder = new Encoder(stream, info.SampleRate, info.Channels, (int)info.PlayLength.TotalSeconds, _comments.Handle); if (info.BitsPerSample > 0) { _encoder.SetLsbDepth(Math.Min(Math.Max(info.BitsPerSample, 8), 24)); } _encoder.SetHeaderGain(gain); if (!settings.TryGetValue("SerialNumber", out int serialNumber)) { serialNumber = new Random().Next(); } _encoder.SetSerialNumber(serialNumber); // Default to full VBR if (settings.TryGetValue("ControlMode", out string vbrMode)) { switch (vbrMode) { case "Variable": _encoder.SetVbrConstraint(false); break; // 'Constrained' is the libopusenc default case "Constant": _encoder.SetVbr(false); break; } } else { _encoder.SetVbrConstraint(false); } if (settings.TryGetValue("BitRate", out int bitRate)) { _encoder.SetBitRate(bitRate); } if (settings.TryGetValue("SignalType", out string signalType)) { _encoder.SetSignal(signalType.Equals("Speech", StringComparison.OrdinalIgnoreCase) ? SignalType.Speech : SignalType.Music); } else { _encoder.SetSignal(SignalType.Music); } }
public void Initialize(Stream stream, AudioInfo info, AudioMetadata metadata, SettingDictionary settings) { _stream = stream; _metadata = metadata; _settings = settings; InitializeReplayGainFilter(info, metadata, settings); var inputDescription = GetInputDescription(info); _audioFile = new ExtendedAudioFile(GetOutputDescription(inputDescription), AudioFileType.M4A, stream); _audioFile.SetProperty(ExtendedAudioFilePropertyId.ClientDataFormat, inputDescription); var converter = _audioFile.GetProperty <IntPtr>(ExtendedAudioFilePropertyId.AudioConverter); var logger = LoggerManager.LoggerFactory.CreateLogger <AacAudioEncoder>(); // Enable high quality (defaults to medium, 0x40) SetConverterProperty(converter, AudioConverterPropertyId.CodecQuality, 0x60); if (settings.TryGetValue("BitRate", out int bitRate)) { if (bitRate > 256 && info.Channels == 1) { logger.LogWarning("The maximum bitrate for 1-channel audio is 256 kbps."); bitRate = 256; } else if (bitRate < 64 && info.Channels == 2) { logger.LogWarning("The minimum bitrate for 2-channel audio is 64 kbps."); bitRate = 64; } SetConverterProperty(converter, AudioConverterPropertyId.BitRate, bitRate * 1000); // Set the control mode (constrained is the default) var controlMode = BitrateControlMode.VariableConstrained; if (settings.TryGetValue("ControlMode", out string controlModeValue)) { if (controlModeValue.Equals("Average", StringComparison.OrdinalIgnoreCase)) { controlMode = BitrateControlMode.LongTermAverage; } else if (controlModeValue.Equals("Constant", StringComparison.OrdinalIgnoreCase)) { controlMode = BitrateControlMode.Constant; } } SetConverterProperty(converter, AudioConverterPropertyId.BitRateControlMode, (uint)controlMode); } else { // Enable a true variable bitrate SetConverterProperty(converter, AudioConverterPropertyId.BitRateControlMode, (uint)BitrateControlMode.Variable); // Use a default VBR quality index of 9 SetConverterProperty(converter, AudioConverterPropertyId.VbrQuality, settings.TryGetValue("VBRQuality", out int quality) ? _vbrQualities[quality] : _vbrQualities[9]); } // Setting the ConverterConfig property to null resynchronizes the converter settings _audioFile.SetProperty(ExtendedAudioFilePropertyId.ConverterConfig, IntPtr.Zero); }