Skip to content

Commit

Permalink
Add configurable audio resample quality option, defaults to High
Browse files Browse the repository at this point in the history
Previous default resample quality is the same as the new Medium setting. Low is the fastest setting and matches in the quality with some other BMS players out there. High setting should be quite good while Highest being the slowest and not much better than the High setting.
  • Loading branch information
GoaLitiuM committed Oct 6, 2016
1 parent ce13b7d commit 968512a
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 11 deletions.
8 changes: 6 additions & 2 deletions Pulsus/Audio/AudioEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ public SoundInstanceInternal(SoundInstance instance)
long buffersMixedCount = 0;
float volume = 1.0f;

public AudioEngine(string audioDevice = null, AudioDriver driver = AudioDriver.Default, int sampleRate = 44100, int bufferLength = 1024)
private ResampleQuality resampleQuality;

public AudioEngine(string audioDevice = null, AudioDriver driver = AudioDriver.Default, int sampleRate = 44100, int bufferLength = 1024, ResampleQuality resampleQuality = ResampleQuality.High)
{
this.resampleQuality = resampleQuality;

SDL.SDL_InitSubSystem(SDL.SDL_INIT_AUDIO);

audioCallback = AudioCallback;
Expand Down Expand Up @@ -261,7 +265,7 @@ public uint GetBufferOffset()
public SoundData LoadFromFile(string path)
{
return new SoundData(FFmpeg.FFmpegHelper.SoundFromFileResample(path,
audioSpec.freq, audioSpec.channels, audioSpec.format));
audioSpec.freq, audioSpec.channels, audioSpec.format, resampleQuality));
}

public void Play(SoundInstance soundInstance, int polyphony)
Expand Down
22 changes: 21 additions & 1 deletion Pulsus/FFmpeg/FFmpegContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ private void SetupCodecContext(AVStream* stream)
format = (int)codecContext->sample_fmt;
}

public void ConvertToFormat(AVSampleFormat sampleFormat, int sampleRate, int channels)
public void ConvertToFormat(AVSampleFormat sampleFormat, int sampleRate, int channels, ResampleQuality resampleQuality = ResampleQuality.High)
{
if (format == (int)sampleFormat &&
this.sampleRate == sampleRate &&
Expand All @@ -312,6 +312,7 @@ public void ConvertToFormat(AVSampleFormat sampleFormat, int sampleRate, int cha
int channelLayout = (int)ffmpeg.av_get_default_channel_layout(channels);

swrContext = ffmpeg.swr_alloc();

ffmpeg.av_opt_set_int(swrContext, "in_channel_layout", (int)codecContext->channel_layout, 0);
ffmpeg.av_opt_set_int(swrContext, "out_channel_layout", channelLayout, 0);
ffmpeg.av_opt_set_int(swrContext, "in_channel_count", codecContext->channels, 0);
Expand All @@ -321,6 +322,25 @@ public void ConvertToFormat(AVSampleFormat sampleFormat, int sampleRate, int cha
ffmpeg.av_opt_set_sample_fmt(swrContext, "in_sample_fmt", codecContext->sample_fmt, 0);
ffmpeg.av_opt_set_sample_fmt(swrContext, "out_sample_fmt", sampleFormat, 0);

switch (resampleQuality)
{
case ResampleQuality.Low:
ffmpeg.av_opt_set_int(swrContext, "filter_size", 0, 0);
ffmpeg.av_opt_set_int(swrContext, "phase_shift", 0, 0);
break;
case ResampleQuality.Medium:
// default ffmpeg settings
break;
case ResampleQuality.High:
ffmpeg.av_opt_set_int(swrContext, "filter_size", 128, 0);
ffmpeg.av_opt_set_double(swrContext, "cutoff", 1.0, 0);
break;
case ResampleQuality.Highest:
ffmpeg.av_opt_set_int(swrContext, "filter_size", 256, 0);
ffmpeg.av_opt_set_double(swrContext, "cutoff", 1.0, 0);
break;
}

if (ffmpeg.swr_init(swrContext) != 0)
throw new ApplicationException("Failed init SwrContext: " + FFmpegHelper.logLastLine);
}
Expand Down
4 changes: 2 additions & 2 deletions Pulsus/FFmpeg/FFmpegHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public static byte[] SoundFromFile(string path, out int sampleRate, out int chan
}
}

public static byte[] SoundFromFileResample(string path, int sampleRate, int channels, ushort sampleFormatSDL)
public static byte[] SoundFromFileResample(string path, int sampleRate, int channels, ushort sampleFormatSDL, ResampleQuality resampleQuality = ResampleQuality.High)
{
AVSampleFormat targetFormat2;
switch (sampleFormatSDL)
Expand All @@ -157,7 +157,7 @@ public static byte[] SoundFromFileResample(string path, int sampleRate, int chan
ffContext.SelectStream(AVMediaType.AVMEDIA_TYPE_AUDIO);

// setup resamplers and other format converters if needed
ffContext.ConvertToFormat(targetFormat2, sampleRate, channels);
ffContext.ConvertToFormat(targetFormat2, sampleRate, channels, resampleQuality);

// FFmpeg only approximates stream durations but is
// usually not far from the real duration.
Expand Down
4 changes: 3 additions & 1 deletion Pulsus/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public Game()
FFmpegHelper.Init();

Log.Info("Initializing Audio...");
audio = new AudioEngine(null, settings.audio.driver, (int)settings.audio.sampleRate, (int)settings.audio.bufferLength);
audio = new AudioEngine(null, settings.audio.driver,
(int)settings.audio.sampleRate, (int)settings.audio.bufferLength,
settings.audio.resampleQuality);
audio.SetVolume(Math.Min(settings.audio.volume, 100) / 100.0f);
Log.Info("Audio driver: " + audio.audioDriver.ToString());

Expand Down
1 change: 1 addition & 0 deletions Pulsus/Pulsus.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
<Compile Include="Graphics\VertexColor.cs" />
<Compile Include="Scenes\Scene.cs" />
<Compile Include="SceneManager.cs" />
<Compile Include="Shared\ResampleQuality.cs" />
<Compile Include="Shared\Settings.cs" />
<Compile Include="Shared\SettingsManager.cs" />
<Compile Include="SettingsWindow.cs" />
Expand Down
10 changes: 10 additions & 0 deletions Pulsus/Shared/ResampleQuality.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Pulsus
{
public enum ResampleQuality
{
Low,
Medium,
High,
Highest,
}
}
8 changes: 4 additions & 4 deletions Pulsus/Shared/Settings.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Jil;
using System;
using System.Collections.Generic;
using Jil;
using Pulsus.Audio;
using Pulsus.Gameplay;
using Pulsus.Graphics;
using Pulsus.Input;
using SDL2;
using System.Collections.Generic;
using System;

namespace Pulsus
{
Expand Down Expand Up @@ -82,10 +82,10 @@ public class VideoSettings
public class AudioSettings
{
public AudioDriver driver = AudioDriver.Default;

public uint volume = 30;
public uint sampleRate = 44100;
public uint bufferLength = 768;
public ResampleQuality resampleQuality = ResampleQuality.Low;
}

public class InputSettings
Expand Down
23 changes: 22 additions & 1 deletion Pulsus/Shared/SettingsParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ private Settings settings
}
}

private bool resampleQualityOverridden = false;

public Settings Parse(string[] args)
{
for (int i = 1; i < args.Length; i++)
Expand Down Expand Up @@ -67,12 +69,17 @@ private static void PrintHelp()
Tuple.Create("-m VALUE, --measure VALUE", "Starts the chart from measure number VALUE [0-999]"),
Tuple.Create("", ""),
Tuple.Create("--render OUTPUT.wav", "Renders all audio of CHARTFILE to file"),
Tuple.Create("--resample-quality [low|medium|high|highest]",
"Changes resampling quality of audio samples"),
Tuple.Create("--dump-timestamps OUTPUT", "Dumps all generated note event timestamps of CHARTFILE"),
};

foreach (var option in options)
{
Console.WriteLine(" {0,-35}{1}", option.Item1, option.Item2);
if (option.Item1.Length < 35)
Console.WriteLine(" {0,-35}{1}", option.Item1, option.Item2);
else
Console.WriteLine(" {0,-35}\n {2,-35}{1}", option.Item1, option.Item2, "");
}

Console.Write("\n");
Expand Down Expand Up @@ -127,6 +134,20 @@ public bool ParseArg(string key, string value)
settings.audio.volume = 100;
settings.outputPath = value;

if (!resampleQualityOverridden)
settings.audio.resampleQuality = ResampleQuality.Highest;
break;
case "--resample-quality":
{
ResampleQuality resampleQuality;
if (Enum.TryParse<ResampleQuality>(value, true, out resampleQuality))
{
settings.audio.resampleQuality = resampleQuality;
resampleQualityOverridden = true;
}
else
Log.Warning("Unknown resample quality value: " + value);
}
break;
case "--dump-timestamps":
settings.outputMode = OutputMode.DumpTimestamps;
Expand Down

0 comments on commit 968512a

Please sign in to comment.