diff --git a/BassAudio.Tests/Integration/AudioEncoderTests.cs b/BassAudio.Tests/Integration/AudioEncoderTests.cs
index 57e8c10b..568f853c 100644
--- a/BassAudio.Tests/Integration/AudioEncoderTests.cs
+++ b/BassAudio.Tests/Integration/AudioEncoderTests.cs
@@ -218,6 +218,27 @@ public async Task Start_Bitrate_CreateFileOfSize(EncodeFormat format, int bitrat
var fileLength = FileSystem.FileInfo.New(file.Destination).Length;
Output.WriteLine(fileLength.ToString());
}
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(32)]
+ [InlineData(128)]
+ [InlineData(256)]
+ [InlineData(320)]
+ public async Task Start_FixedBitrate_CreateFileOfSize(int bitrate)
+ {
+ var file = CreateSourceShort(EncodeFormat.Mp3);
+ FileSystem.DeleteFileSilent(file.Destination);
+ Settings.Format = EncodeFormat.Mp3;
+ Settings.FixedBitrate = true;
+ Settings.Bitrate = bitrate;
+
+ await Model.StartAsync(file, Settings);
+
+ Assert.True(FileSystem.File.Exists(file.Destination));
+ var fileLength = FileSystem.FileInfo.New(file.Destination).Length;
+ Output.WriteLine(fileLength.ToString());
+ }
[Theory]
[MemberData(nameof(GetAllSampleRates))]
diff --git a/BassAudio/AudioEncoder.cs b/BassAudio/AudioEncoder.cs
index e44371dd..ee7cc8fe 100644
--- a/BassAudio/AudioEncoder.cs
+++ b/BassAudio/AudioEncoder.cs
@@ -3,6 +3,7 @@
using ManagedBass.Enc;
using ManagedBass.Fx;
using ManagedBass.Mix;
+
// ReSharper disable StringLiteralTypo
namespace HanumanInstitute.BassAudio;
@@ -46,10 +47,10 @@ public void Start(ProcessingItem file, EncodeSettings settings, CancellationToke
{
file.Pitch ??= _pitchDetector.GetPitch(file.Path);
}
- var pitch = settings.AutoDetectPitch ?
- settings.PitchTo / file.Pitch!.Value :
+ var pitch = settings.AutoDetectPitch ?
+ settings.PitchTo / file.Pitch!.Value :
settings.Pitch;
-
+
// Create channel.
Bass.Configure(Configuration.SRCQuality, 4);
Bass.Configure(Configuration.FloatDSP, true);
@@ -59,12 +60,12 @@ public void Start(ProcessingItem file, EncodeSettings settings, CancellationToke
try
{
var tags = new TagsReader(chan);
-
+
var chanInfo = Bass.ChannelGetInfo(chan);
var bitrate = (int)Bass.ChannelGetAttribute(chan, ChannelAttribute.Bitrate);
bitrate = BitrateRoundUp(bitrate);
var length = Bass.ChannelGetLength(chan);
-
+
// Add mix effect.
var sampleRate = settings.SampleRate > 0 ? settings.SampleRate : chanInfo.Frequency;
sampleRate = EnsureSampleRateValid(settings.Format, sampleRate);
@@ -83,7 +84,7 @@ public void Start(ProcessingItem file, EncodeSettings settings, CancellationToke
// Bass.ChannelSetAttribute(chan, ChannelAttribute.Tempo, (1.0 / pitch * settings.Speed - 1.0) * 100.0);
// Bass.ChannelSetAttribute(chan, ChannelAttribute.TempoFrequency,
// chanInfo.Frequency * pitch * settings.Rate);
-
+
// Optimized pitch shifting for increased quality
// 1. Rate shift to Output * Pitch (rounded)
// 2. Resample to Output (48000Hz)
@@ -183,11 +184,13 @@ private string GetOptions(EncodeSettings settings, int sourceBitrate, ChannelInf
return settings.Format switch
{
- EncodeFormat.Mp3 => $"--abr {bitrate} -q {settings.Mp3QualitySpeed} --add-id3v2"
- .AddTag("--tt", tags.Title).AddTag("--ta", tags.Artist).AddTag("--tl", tags.Album).AddTag("--ty", tags.Year)
+ EncodeFormat.Mp3 => (settings.FixedBitrate ? "-b" : "--abr") + $" {bitrate} -q {settings.Mp3QualitySpeed} --add-id3v2"
+ .AddTag("--tt", tags.Title).AddTag("--ta", tags.Artist).AddTag("--tl", tags.Album)
+ .AddTag("--ty", tags.Year)
.AddTag("--tc", tags.Comment).AddTag("--tn", tags.Track).AddTag("--tg", tags.Genre),
EncodeFormat.Flac => $"--compression-level-{settings.FlacCompression}"
- .AddTag("-T title=", tags.Title).AddTag("-T artist=", tags.Artist).AddTag("-T album=", tags.Album).AddTag("--date", tags.Year)
+ .AddTag("-T title=", tags.Title).AddTag("-T artist=", tags.Artist).AddTag("-T album=", tags.Album)
+ .AddTag("--date", tags.Year)
.AddTag("-T comment=", tags.Comment).AddTag("-T tracknum=", tags.Track).AddTag("-T genre=", tags.Genre),
EncodeFormat.Ogg => $"--bitrate {bitrate}"
.AddTag("--title", tags.Title).AddTag("--artist", tags.Artist).AddTag("--album", tags.Album).AddTag("--date", tags.Year)
diff --git a/BassAudio/Models/EncodeSettings.cs b/BassAudio/Models/EncodeSettings.cs
index d3f570db..105746ae 100644
--- a/BassAudio/Models/EncodeSettings.cs
+++ b/BassAudio/Models/EncodeSettings.cs
@@ -1,4 +1,4 @@
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using ReactiveUI;
namespace HanumanInstitute.BassAudio;
@@ -20,11 +20,17 @@ public class EncodeSettings : ReactiveObject
[Reactive]
public int Bitrate { get; set; }
+ ///
+ /// Gets or sets whether to encode as fixed bitrate.
+ ///
+ [Reactive]
+ public bool FixedBitrate { get; set; }
+
///
/// Gets or sets the encoding bits per sample for WAV or FLAC formats. Valid values are 0 (auto), 8, 16, 24 or 32.
///
[Reactive]
- public int BitsPerSample { get; set; }
+ public int BitsPerSample { get; set; } = 16;
///
/// Gets or sets the encoding sample rate.
diff --git a/Common.Avalonia.App/Common.Avalonia.App.csproj b/Common.Avalonia.App/Common.Avalonia.App.csproj
index 8bb8babf..ecb8b85d 100644
--- a/Common.Avalonia.App/Common.Avalonia.App.csproj
+++ b/Common.Avalonia.App/Common.Avalonia.App.csproj
@@ -49,12 +49,5 @@
-
-
-
-
- AboutView.axaml
- Code
-
diff --git a/Common.Avalonia/Converters/BooleanToBrushConverter.cs b/Common.Avalonia/Converters/BooleanToBrushConverter.cs
index 7e0dbfc9..a60d3b32 100644
--- a/Common.Avalonia/Converters/BooleanToBrushConverter.cs
+++ b/Common.Avalonia/Converters/BooleanToBrushConverter.cs
@@ -3,7 +3,7 @@
namespace HanumanInstitute.Common.Avalonia;
///
-/// Converts boolean values to string while allowing to configure true and false values.
+/// Converts boolean values to brush while allowing to configure true and false values.
///
public sealed class BooleanToBrushConverter : BooleanConverter
{
diff --git a/Converter432Hz/ViewModels/MainViewModel.cs b/Converter432Hz/ViewModels/MainViewModel.cs
index 4b975b96..1827111c 100644
--- a/Converter432Hz/ViewModels/MainViewModel.cs
+++ b/Converter432Hz/ViewModels/MainViewModel.cs
@@ -45,6 +45,8 @@ public MainViewModel(ISettingsProvider settings, IAppUpdateServ
_isBitrateVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x != EncodeFormat.Flac && x != EncodeFormat.Wav)
.ToProperty(this, x => x.IsBitrateVisible);
+ _isToggleBitrateVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x == EncodeFormat.Mp3)
+ .ToProperty(this, x => x.IsToggleBitrateVisible);
_isBitsPerSampleVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x == EncodeFormat.Flac || x == EncodeFormat.Wav)
.ToProperty(this, x => x.IsBitsPerSampleVisible);
_isQualitySpeedVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x == EncodeFormat.Mp3 || x == EncodeFormat.Flac)
@@ -95,6 +97,12 @@ private void Bind(Expression> expr1, Expression
public bool IsBitrateVisible => _isBitrateVisible.Value;
private readonly ObservableAsPropertyHelper _isBitrateVisible;
+ ///
+ /// Gets or sets whether Toggle Bitrate button should be visible.
+ ///
+ public bool IsToggleBitrateVisible => _isToggleBitrateVisible.Value;
+ private readonly ObservableAsPropertyHelper _isToggleBitrateVisible;
+
///
/// Gets whether Bits Per Sample control should be visible.
///
@@ -256,6 +264,16 @@ private void FillSampleRateList(EncodeFormat format)
{ FileExistsAction.Rename, "Rename" },
{ FileExistsAction.Cancel, "Cancel" }
};
+
+ ///
+ /// Enables or disables the Fixed Bitrate option.
+ ///
+ public RxCommandUnit ToggleFixedBitrate => _toggleFixedBitrate ??= ReactiveCommand.Create(ToggleFixedBitrateImpl);
+ private RxCommandUnit? _toggleFixedBitrate;
+ private void ToggleFixedBitrateImpl()
+ {
+ Settings.Encode.FixedBitrate = !Settings.Encode.FixedBitrate;
+ }
///
/// Starts the batch encoding job.
diff --git a/Converter432Hz/Views/MainView.axaml b/Converter432Hz/Views/MainView.axaml
index 6c8c3585..f4b87976 100644
--- a/Converter432Hz/Views/MainView.axaml
+++ b/Converter432Hz/Views/MainView.axaml
@@ -18,6 +18,7 @@
d:DataContext="{x:Static local:ViewModelLocator.Main}" x:DataType="vm:MainViewModel">
+
@@ -101,7 +102,12 @@
-
+
+
+
+
diff --git a/YangDownloader/ViewModels/EncodeSettingsViewModel.cs b/YangDownloader/ViewModels/EncodeSettingsViewModel.cs
index a0730d2e..74f186b1 100644
--- a/YangDownloader/ViewModels/EncodeSettingsViewModel.cs
+++ b/YangDownloader/ViewModels/EncodeSettingsViewModel.cs
@@ -27,6 +27,8 @@ public EncodeSettingsViewModel(IAudioEncoder encoder, IEnvironmentService enviro
_isBitrateVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x != EncodeFormat.Flac && x != EncodeFormat.Wav)
.ToProperty(this, x => x.IsBitrateVisible);
+ _isToggleBitrateVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x == EncodeFormat.Mp3)
+ .ToProperty(this, x => x.IsToggleBitrateVisible);
_isBitsPerSampleVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x == EncodeFormat.Flac || x == EncodeFormat.Wav)
.ToProperty(this, x => x.IsBitsPerSampleVisible);
_isQualitySpeedVisible = this.WhenAnyValue(x => x.FormatsList.SelectedValue, x => x == EncodeFormat.Mp3 || x == EncodeFormat.Flac)
@@ -85,6 +87,12 @@ public bool ShiftPitch
public bool IsBitrateVisible => _isBitrateVisible.Value;
private readonly ObservableAsPropertyHelper _isBitrateVisible;
+ ///
+ /// Gets or sets whether Toggle Bitrate button should be visible.
+ ///
+ public bool IsToggleBitrateVisible => _isToggleBitrateVisible.Value;
+ private readonly ObservableAsPropertyHelper _isToggleBitrateVisible;
+
///
/// Gets whether Bits Per Sample control should be visible.
///
@@ -141,6 +149,16 @@ private void FillSampleRateList(EncodeFormat format)
{ 32, "32-bits" }
};
+ ///
+ /// Enables or disables the Fixed Bitrate option.
+ ///
+ public RxCommandUnit ToggleFixedBitrate => _toggleFixedBitrate ??= ReactiveCommand.Create(ToggleFixedBitrateImpl);
+ private RxCommandUnit? _toggleFixedBitrate;
+ private void ToggleFixedBitrateImpl()
+ {
+ Settings.FixedBitrate = !Settings.FixedBitrate;
+ }
+
///
/// Restores default settings.
///
diff --git a/YangDownloader/Views/EncodeSettingsView.axaml b/YangDownloader/Views/EncodeSettingsView.axaml
index 572350e2..10a0ad35 100644
--- a/YangDownloader/Views/EncodeSettingsView.axaml
+++ b/YangDownloader/Views/EncodeSettingsView.axaml
@@ -4,11 +4,15 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HanumanInstitute.YangDownloader"
xmlns:vm="clr-namespace:HanumanInstitute.YangDownloader.ViewModels"
+ xmlns:hic="clr-namespace:HanumanInstitute.Common.Avalonia;assembly=Common.Avalonia"
mc:Ignorable="d" MinWidth="280" Width="280" MaxWidth="280" MinHeight="420" Height="420" MaxHeight="420"
x:Class="HanumanInstitute.YangDownloader.Views.EncodeSettingsView"
Title="Advanced Settings" Classes="gradient"
CanResize="False" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
d:DataContext="{x:Static local:ViewModelLocator.EncodeSettings}" x:DataType="vm:EncodeSettingsViewModel">
+
+
+
@@ -19,7 +23,12 @@
-
+
+
+
+