Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ReplayGain Feature #936

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions game/languages/English.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
OPTION_VALUE_GAIN_SOFT=Soft
OPTION_VALUE_GAIN_MEDIUM=Medium
OPTION_VALUE_GAIN_HARD=Hard
OPTION_VALUE_GAIN_REPLAYGAIN=ReplayGain

OPTION_VALUE_AUTO=Auto
OPTION_VALUE_SEC=Second
Expand Down
1 change: 1 addition & 0 deletions game/languages/Language.new
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
;TODO: OPTION_VALUE_GAIN_SOFT=Soft
;TODO: OPTION_VALUE_GAIN_MEDIUM=Medium
;TODO: OPTION_VALUE_GAIN_HARD=Hard
;TODO: OPTION_VALUE_GAIN_REPLAYGAIN=ReplayGain

;TODO: OPTION_VALUE_AUTO=Auto
;TODO: OPTION_VALUE_SEC=Second
Expand Down
10 changes: 6 additions & 4 deletions src/base/UIni.pas
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ TInputDeviceConfig = record
TVisualizerOption = (voOff, voWhenNoVideo, voWhenNoVideoAndImage, voOn);
TBackgroundMusicOption = (bmoOff, bmoOn);
TSongMenuMode = ( smRoulette, smChessboard, smCarousel, smSlotMachine, smSlide, smList, smMosaic);
TMusicAutoGainOption = (magOff, {$IFDEF HaveBASS} magSoft, magMedium, magHard, {$ENDIF} magReplayGain);

TIni = class
private
Expand Down Expand Up @@ -371,9 +372,7 @@ TIni = class

IVoicePassthrough: array[0..1] of UTF8String = ('Off', 'On');

IMusicAutoGain: array[0..3] of UTF8String = ('Off', 'Soft', 'Medium', 'Hard');
IMusicAutoGainVals: array[0..3] of integer = (-1, 0, 1, 2);

IMusicAutoGain: array[0..{$IFDEF HaveBASS}4{$ELSE}1{$ENDIF}] of UTF8String = ('Off', {$IFDEF HaveBASS} 'Soft', 'Medium', 'Hard', {$ENDIF} 'ReplayGain');

const
ISyncTo: array[0..2] of UTF8String = ('Music', 'Lyrics', 'Off');
Expand Down Expand Up @@ -497,7 +496,7 @@ TIni = class

IVoicePassthroughTranslated: array[0..1] of UTF8String = ('Off', 'On');

IMusicAutoGainTranslated: array[0..3] of UTF8String = ('Off', 'Soft', 'Medium', 'Hard');
IMusicAutoGainTranslated: array[0..{$IFDEF HaveBASS}4{$ELSE}1{$ENDIF}] of UTF8String = ('Off', {$IFDEF HaveBASS} 'Soft', 'Medium', 'Hard', {$ENDIF} 'ReplayGain');

ISyncToTranslated: array[0..2] of UTF8String = ('Music', 'Lyrics', 'Off');

Expand Down Expand Up @@ -684,9 +683,12 @@ procedure TIni.TranslateOptionValues;
IVoicePassthroughTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_ON');

IMusicAutoGainTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_OFF');
{$IFDEF HaveBass}
IMusicAutoGainTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_GAIN_SOFT');
IMusicAutoGainTranslated[2] := ULanguage.Language.Translate('OPTION_VALUE_GAIN_MEDIUM');
IMusicAutoGainTranslated[3] := ULanguage.Language.Translate('OPTION_VALUE_GAIN_HARD');
{$ENDIF}
IMusicAutoGainTranslated[{$IFDEF HaveBass}4{$ELSE}1{$ENDIF}] := ULanguage.Language.Translate('OPTION_VALUE_GAIN_REPLAYGAIN');

ISyncToTranslated[Ord(stMusic)] := ULanguage.Language.Translate('OPTION_VALUE_MUSIC');
ISyncToTranslated[Ord(stLyrics)] := ULanguage.Language.Translate('OPTION_VALUE_LYRICS');
Expand Down
61 changes: 59 additions & 2 deletions src/base/UMusic.pas
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ TSoundFX = class

end;

TReplayGain = class(TSoundFX)
TAutoGain = class(TSoundFX)
end;

type
Expand Down Expand Up @@ -286,6 +286,7 @@ TAudioSourceStream = class(TAudioProcessingStream)
function IsError(): boolean; virtual; abstract;
public
function ReadData(Buffer: PByte; BufferSize: integer): integer; virtual; abstract;
function GetReplayGain(): single; virtual;

property EOF: boolean read IsEOF;
property Error: boolean read IsError;
Expand All @@ -309,6 +310,8 @@ TAudioPlaybackStream = class(TAudioProcessingStream)
AvgSyncDiff: double; //** average difference between stream and sync clock
SyncSource: TSyncSource;
SourceStream: TAudioSourceStream;
RG: single;
RGEnabled: boolean;

function GetLatency(): double; virtual; abstract;
function GetStatus(): TStreamStatus; virtual; abstract;
Expand All @@ -317,6 +320,8 @@ TAudioPlaybackStream = class(TAudioProcessingStream)
function Synchronize(BufferSize: integer; FormatInfo: TAudioFormatInfo): integer;
procedure FillBufferWithFrame(Buffer: PByteArray; BufferSize: integer; Frame: PByteArray; FrameSize: integer);
public
constructor Create();

(**
* Opens a SourceStream for playback.
* Note that the caller (not the TAudioPlaybackStream) is responsible to
Expand All @@ -325,7 +330,7 @@ TAudioPlaybackStream = class(TAudioProcessingStream)
* guarantees to deliver this method's SourceStream parameter to
* the OnClose-handler. Freeing SourceStream at OnClose is allowed.
*)
function Open(SourceStream: TAudioSourceStream): boolean; virtual; abstract;
function Open(SourceStream: TAudioSourceStream): boolean; virtual;

procedure Play(); virtual; abstract;
procedure Pause(); virtual; abstract;
Expand All @@ -342,8 +347,14 @@ TAudioPlaybackStream = class(TAudioProcessingStream)
procedure SetSyncSource(SyncSource: TSyncSource);
function GetSourceStream(): TAudioSourceStream;

function GetRGAdjustment(): single;
procedure SetRGAdjustment(Adjustment: single);
procedure EnableReplayGain() virtual;
procedure DisableReplayGain() virtual;

property Status: TStreamStatus read GetStatus;
property Volume: single read GetVolume write SetVolume;
property RGAdjustment: single read GetRGAdjustment write SetRGAdjustment;
end;

TAudioDecodeStream = class(TAudioSourceStream)
Expand Down Expand Up @@ -1075,9 +1086,29 @@ procedure TAudioProcessingStream.PerformOnClose();
end;
end;

{ TAudioSourceStream }

function TAudioSourceStream.GetReplayGain(): single;
begin
Result := 1.0;
end;

{ TAudioPlaybackStream }

constructor TAudioPlaybackStream.Create();
begin
RG := 1.0;
RGEnabled := false;
inherited;
end;

function TAudioPlaybackStream.Open(SourceStream: TAudioSourceStream): boolean;
begin
if (Ini.MusicAutoGain = ord(magReplayGain)) then
RGAdjustment := SourceStream.GetReplayGain();
Result := true;
end;

function TAudioPlaybackStream.GetSourceStream(): TAudioSourceStream;
begin
Result := SourceStream;
Expand Down Expand Up @@ -1209,6 +1240,32 @@ procedure TAudioPlaybackStream.FillBufferWithFrame(Buffer: PByteArray; BufferSiz
Move(Frame[0], Buffer[i*FrameSize], FrameSize);
end;

procedure TAudioPlaybackStream.SetRGAdjustment(Adjustment: single);
begin
if ((Adjustment > 0.0) AND (Adjustment <= 1.0)) then
begin
RG := Adjustment;
end;
end;

function TAudioPlaybackStream.GetRGAdjustment(): single;
begin
if (RGEnabled) then
Result := RG
else
Result := 1.0;
end;

procedure TAudioPlaybackStream.EnableReplayGain();
begin
RGEnabled := true;
end;

procedure TAudioPlaybackStream.DisableReplayGain();
begin
RGEnabled := false;
end;

{ TAudioVoiceStream }

function TAudioVoiceStream.Open(ChannelMap: integer; FormatInfo: TAudioFormatInfo): boolean;
Expand Down
16 changes: 15 additions & 1 deletion src/lib/ffmpeg-5.0/avformat.pas
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ TAVFormatContext = record
we_do_not_use_packet_size: cuint;
we_do_not_use_max_delay: cint;
flags: cint;
we_do_not_use_probesize: cint64;
we_do_not_use_max_analyze_duration: cint64;
we_do_not_use_key: pointer;
we_do_not_use_keylen: cint;
we_do_not_use_nb_programs: cuint;
we_do_not_use_programs: pointer;
we_do_not_use_video_codec_id: cenum;
we_do_not_use_audio_codec_id: cenum;
we_do_not_use_subtitle_codec_id: cenum;
we_do_not_use_max_index_size: cuint;
we_do_not_use_max_picture_buffer: cuint;
we_do_not_use_nb_chapters: cuint;
we_do_not_use_chapters: pointer;
metadata: PAVDictionary;
do_not_instantiate_this_record: incomplete_record;
end;
TAVStream = record
Expand All @@ -93,7 +107,7 @@ TAVStream = record
we_do_not_use_disposition: cint;
we_do_not_use_discard: cenum;
we_do_not_use_sample_aspect_ratio: TAVRational;
we_do_not_use_metadata: PAVDictionary;
metadata: PAVDictionary;
we_do_not_use_avg_frame_rate: TAVRational;
we_do_not_use_atached_pic: TAVPacket;
we_do_not_use_side_data: pointer;
Expand Down
6 changes: 6 additions & 0 deletions src/lib/ffmpeg-5.0/avutil.pas
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ TAVFrame = record
TAVDictionary = record
do_not_instantiate_this_record: incomplete_record;
end;
PAVDictionaryEntry = ^TAVDictionaryEntry;
TAVDictionaryEntry = record
key: PAnsiChar;
value: PAnsiChar;
end;
procedure av_free(ptr: pointer); cdecl; external av__util;
procedure av_freep(ptr: pointer); cdecl; external av__util;
function av_malloc(size: csize_t): pointer; cdecl; external av__util;
Expand All @@ -169,6 +174,7 @@ function av_samples_alloc(var audio_data: pcuint8; linesize: pcint; nb_channels:
function av_get_packed_sample_fmt(sample_fmt: TAVSampleFormat): TAVSampleFormat; cdecl; external av__util;
function av_get_bytes_per_sample(sample_fmt: TAVSampleFormat): cint; cdecl; external av__util;
procedure av_log_set_level(level: cint); cdecl; external av__util;
function av_dict_get(m: PAVDictionary; const key: PAnsiChar; prev: PAVDictionaryEntry; flags: cint): PAVDictionaryEntry; cdecl; external av__util;
implementation
function AVERROR(e: cint): cint; {$IFDEF HasInline}inline;{$ENDIF}
begin
Expand Down
16 changes: 15 additions & 1 deletion src/lib/ffmpeg-6.0/avformat.pas
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ TAVFormatContext = record
we_do_not_use_packet_size: cuint;
we_do_not_use_max_delay: cint;
flags: cint;
we_do_not_use_probesize: cint64;
we_do_not_use_max_analyze_duration: cint64;
we_do_not_use_key: pointer;
we_do_not_use_keylen: cint;
we_do_not_use_nb_programs: cuint;
we_do_not_use_programs: pointer;
we_do_not_use_video_codec_id: cenum;
we_do_not_use_audio_codec_id: cenum;
we_do_not_use_subtitle_codec_id: cenum;
we_do_not_use_max_index_size: cuint;
we_do_not_use_max_picture_buffer: cuint;
we_do_not_use_nb_chapters: cuint;
we_do_not_use_chapters: pointer;
metadata: PAVDictionary;
do_not_instantiate_this_record: incomplete_record;
end;
TAVStream = record
Expand All @@ -90,7 +104,7 @@ TAVStream = record
we_do_not_use_disposition: cint;
we_do_not_use_discard: cenum;
we_do_not_use_sample_aspect_ratio: TAVRational;
we_do_not_use_metadata: PAVDictionary;
metadata: PAVDictionary;
we_do_not_use_avg_frame_rate: TAVRational;
we_do_not_use_attached_pic: TAVPacket;
we_do_not_use_side_data: pointer;
Expand Down
6 changes: 6 additions & 0 deletions src/lib/ffmpeg-6.0/avutil.pas
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ TAVFrame = record
TAVDictionary = record
do_not_instantiate_this_record: incomplete_record;
end;
PAVDictionaryEntry = ^TAVDictionaryEntry;
TAVDictionaryEntry = record
key: PAnsiChar;
value: PAnsiChar;
end;
procedure av_free(ptr: pointer); cdecl; external av__util;
procedure av_freep(ptr: pointer); cdecl; external av__util;
function av_malloc(size: csize_t): pointer; cdecl; external av__util;
Expand All @@ -169,6 +174,7 @@ function av_samples_alloc(var audio_data: pcuint8; linesize: pcint; nb_channels:
function av_get_packed_sample_fmt(sample_fmt: TAVSampleFormat): TAVSampleFormat; cdecl; external av__util;
function av_get_bytes_per_sample(sample_fmt: TAVSampleFormat): cint; cdecl; external av__util;
procedure av_log_set_level(level: cint); cdecl; external av__util;
function av_dict_get(m: PAVDictionary; const key: PAnsiChar; prev: PAVDictionaryEntry; flags: cint): PAVDictionaryEntry; cdecl; external av__util;
implementation
function AVERROR(e: cint): cint; {$IFDEF HasInline}inline;{$ENDIF}
begin
Expand Down
13 changes: 12 additions & 1 deletion src/lib/ffmpeg-7.0/avformat.pas
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ TAVFormatContext = record
we_do_not_use_packet_size: cuint;
we_do_not_use_max_delay: cint;
flags: cint;
we_do_not_use_probesize: cint64;
we_do_not_use_max_analyze_duration: cint64;
we_do_not_use_key: pointer;
we_do_not_use_keylen: cint;
we_do_not_use_nb_programs: cuint;
we_do_not_use_programs: pointer;
we_do_not_use_video_codec_id: cenum;
we_do_not_use_audio_codec_id: cenum;
we_do_not_use_subtitle_codec_id: cenum;
we_do_not_use_data_codec_id: cenum;
metadata: PAVDictionary;
do_not_instantiate_this_record: incomplete_record;
end;
TAVStream = record
Expand All @@ -94,7 +105,7 @@ TAVStream = record
we_do_not_use_disposition: cint;
we_do_not_use_discard: cenum;
we_do_not_use_sample_aspect_ratio: TAVRational;
we_do_not_use_metadata: PAVDictionary;
metadata: PAVDictionary;
we_do_not_use_avg_frame_rate: TAVRational;
we_do_not_use_attached_pic: TAVPacket;
we_do_not_use_side_data: pointer;
Expand Down
6 changes: 6 additions & 0 deletions src/lib/ffmpeg-7.0/avutil.pas
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ TAVChannelLayout = record
TAVDictionary = record
do_not_instantiate_this_record: incomplete_record;
end;
PAVDictionaryEntry = ^TAVDictionaryEntry;
TAVDictionaryEntry = record
key: PAnsiChar;
value: PAnsiChar;
end;
procedure av_channel_layout_default(ch_layout: PAVChannelLayout; nb_channels: cint); cdecl; external av__util;
function av_channel_layout_from_string(channel_layout: PAVChannelLayout; str: PAnsiChar): cint; cdecl; external av__util;
procedure av_free(ptr: pointer); cdecl; external av__util;
Expand All @@ -179,6 +184,7 @@ function av_opt_set_sample_fmt(obj: pointer; name: PAnsiChar; fmt: TAVSampleForm
function av_get_packed_sample_fmt(sample_fmt: TAVSampleFormat): TAVSampleFormat; cdecl; external av__util;
function av_get_bytes_per_sample(sample_fmt: TAVSampleFormat): cint; cdecl; external av__util;
procedure av_log_set_level(level: cint); cdecl; external av__util;
function av_dict_get(m: PAVDictionary; const key: PAnsiChar; prev: PAVDictionaryEntry; flags: cint): PAVDictionaryEntry; cdecl; external av__util;
implementation
function AVERROR(e: cint): cint; {$IFDEF HasInline}inline;{$ENDIF}
begin
Expand Down
Loading