Skip to content

Commit

Permalink
Support fixed bitrate encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
mysteryx93 committed Mar 25, 2023
1 parent 2b394a5 commit 495ac3f
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 21 deletions.
21 changes: 21 additions & 0 deletions BassAudio.Tests/Integration/AudioEncoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down
21 changes: 12 additions & 9 deletions BassAudio/AudioEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using ManagedBass.Enc;
using ManagedBass.Fx;
using ManagedBass.Mix;

// ReSharper disable StringLiteralTypo

namespace HanumanInstitute.BassAudio;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 8 additions & 2 deletions BassAudio/Models/EncodeSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using ReactiveUI;

namespace HanumanInstitute.BassAudio;
Expand All @@ -20,11 +20,17 @@ public class EncodeSettings : ReactiveObject
[Reactive]
public int Bitrate { get; set; }

/// <summary>
/// Gets or sets whether to encode as fixed bitrate.
/// </summary>
[Reactive]
public bool FixedBitrate { get; set; }

/// <summary>
/// Gets or sets the encoding bits per sample for WAV or FLAC formats. Valid values are 0 (auto), 8, 16, 24 or 32.
/// </summary>
[Reactive]
public int BitsPerSample { get; set; }
public int BitsPerSample { get; set; } = 16;

/// <summary>
/// Gets or sets the encoding sample rate.
Expand Down
7 changes: 0 additions & 7 deletions Common.Avalonia.App/Common.Avalonia.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,5 @@
<ItemGroup>
<None Remove="Styles\HanumanInstituteAppIcons.otf" />
<AvaloniaResource Include="Styles\HanumanInstituteAppIcons.otf" />
<AvaloniaXaml Remove="Common\AboutView.axaml" />
<None Include="Common\AboutView.axaml" />
<Compile Remove="Common\AboutView.axaml.cs" />
<None Include="Common\AboutView.axaml.cs">
<DependentUpon>AboutView.axaml</DependentUpon>
<SubType>Code</SubType>
</None>
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Common.Avalonia/Converters/BooleanToBrushConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace HanumanInstitute.Common.Avalonia;

/// <summary>
/// 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.
/// </summary>
public sealed class BooleanToBrushConverter : BooleanConverter<Brush>
{
Expand Down
18 changes: 18 additions & 0 deletions Converter432Hz/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public MainViewModel(ISettingsProvider<AppSettingsData> 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)
Expand Down Expand Up @@ -95,6 +97,12 @@ private void Bind<T1, T2>(Expression<Func<MainViewModel, T1?>> expr1, Expression
public bool IsBitrateVisible => _isBitrateVisible.Value;
private readonly ObservableAsPropertyHelper<bool> _isBitrateVisible;

/// <summary>
/// Gets or sets whether Toggle Bitrate button should be visible.
/// </summary>
public bool IsToggleBitrateVisible => _isToggleBitrateVisible.Value;
private readonly ObservableAsPropertyHelper<bool> _isToggleBitrateVisible;

/// <summary>
/// Gets whether Bits Per Sample control should be visible.
/// </summary>
Expand Down Expand Up @@ -256,6 +264,16 @@ private void FillSampleRateList(EncodeFormat format)
{ FileExistsAction.Rename, "Rename" },
{ FileExistsAction.Cancel, "Cancel" }
};

/// <summary>
/// Enables or disables the Fixed Bitrate option.
/// </summary>
public RxCommandUnit ToggleFixedBitrate => _toggleFixedBitrate ??= ReactiveCommand.Create(ToggleFixedBitrateImpl);
private RxCommandUnit? _toggleFixedBitrate;
private void ToggleFixedBitrateImpl()
{
Settings.Encode.FixedBitrate = !Settings.Encode.FixedBitrate;
}

/// <summary>
/// Starts the batch encoding job.
Expand Down
8 changes: 7 additions & 1 deletion Converter432Hz/Views/MainView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
d:DataContext="{x:Static local:ViewModelLocator.Main}" x:DataType="vm:MainViewModel">
<Window.Resources>
<hic:PercentageConverter x:Key="PercentageConverter" />
<hic:BooleanToStringConverter x:Key="BitrateConverter" TrueValue="CBR" FalseValue="VBR" />
</Window.Resources>
<Grid>
<Grid Margin="10">
Expand Down Expand Up @@ -101,7 +102,12 @@
</ComboBox>
</Grid>
<Grid Margin="0,2,0,2" IsVisible="{Binding IsBitrateVisible}">
<TextBlock VerticalAlignment="Center" Text="Bitrate" />
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="Bitrate" />
<Button Classes="round" Width="40" Margin="10,0,0,0"
Content="{Binding Settings.Encode.FixedBitrate, Converter={StaticResource BitrateConverter}}"
Command="{Binding ToggleFixedBitrate}" IsVisible="{Binding IsToggleBitrateVisible}" />
</StackPanel>
<ComboBox HorizontalAlignment="Right" Width="120" x:CompileBindings="False"
Items="{Binding BitrateList}" SelectedItem="{Binding BitrateList.CurrentItem}">
</ComboBox>
Expand Down
18 changes: 18 additions & 0 deletions YangDownloader/ViewModels/EncodeSettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -85,6 +87,12 @@ public bool ShiftPitch
public bool IsBitrateVisible => _isBitrateVisible.Value;
private readonly ObservableAsPropertyHelper<bool> _isBitrateVisible;

/// <summary>
/// Gets or sets whether Toggle Bitrate button should be visible.
/// </summary>
public bool IsToggleBitrateVisible => _isToggleBitrateVisible.Value;
private readonly ObservableAsPropertyHelper<bool> _isToggleBitrateVisible;

/// <summary>
/// Gets whether Bits Per Sample control should be visible.
/// </summary>
Expand Down Expand Up @@ -141,6 +149,16 @@ private void FillSampleRateList(EncodeFormat format)
{ 32, "32-bits" }
};

/// <summary>
/// Enables or disables the Fixed Bitrate option.
/// </summary>
public RxCommandUnit ToggleFixedBitrate => _toggleFixedBitrate ??= ReactiveCommand.Create(ToggleFixedBitrateImpl);
private RxCommandUnit? _toggleFixedBitrate;
private void ToggleFixedBitrateImpl()
{
Settings.FixedBitrate = !Settings.FixedBitrate;
}

/// <summary>
/// Restores default settings.
/// </summary>
Expand Down
11 changes: 10 additions & 1 deletion YangDownloader/Views/EncodeSettingsView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<Window.Resources>
<hic:BooleanToStringConverter x:Key="BitrateConverter" TrueValue="CBR" FalseValue="VBR" />
</Window.Resources>
<Grid>
<Grid Margin="10">
<StackPanel>
Expand All @@ -19,7 +23,12 @@
</ComboBox>
</Grid>
<Grid Margin="0,2,0,2" Height="24" IsVisible="{Binding IsBitrateVisible}">
<TextBlock VerticalAlignment="Center" Text="Bitrate" />
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="Bitrate" />
<Button Classes="round" Width="40" Margin="10,0,0,0"
Content="{Binding Settings.FixedBitrate, Converter={StaticResource BitrateConverter}}"
Command="{Binding ToggleFixedBitrate}" IsVisible="{Binding IsToggleBitrateVisible}" />
</StackPanel>
<ComboBox HorizontalAlignment="Right" Width="110" x:CompileBindings="False"
Items="{Binding BitrateList}" SelectedItem="{Binding BitrateList.CurrentItem}">
</ComboBox>
Expand Down

0 comments on commit 495ac3f

Please sign in to comment.