aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mediaplugin/src/media/UAudioConverter.pas315
-rw-r--r--mediaplugin/src/media/UMediaPlugin.pas5
-rw-r--r--mediaplugin/src/ultrastardx.dpr7
3 files changed, 9 insertions, 318 deletions
diff --git a/mediaplugin/src/media/UAudioConverter.pas b/mediaplugin/src/media/UAudioConverter.pas
index de6840ca..343d0742 100644
--- a/mediaplugin/src/media/UAudioConverter.pas
+++ b/mediaplugin/src/media/UAudioConverter.pas
@@ -36,10 +36,6 @@ interface
uses
UMusic,
ULog,
- ctypes,
- {$IFDEF UseSRCResample}
- samplerate,
- {$ENDIF}
UMediaPlugin,
UMediaCore_SDL,
sdl,
@@ -76,51 +72,6 @@ type
function GetRatio(): double; override;
end;
- {$IFDEF UseFFmpegResample}
- TAudioConverterPlugin = class(TAudioConverter)
- private
- fPluginInfo: PMediaPluginInfo;
- fAudioConverter: PAudioConverterInfo;
- fStream: PAudioConvertStream;
- public
- function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override;
- destructor Destroy(); override;
-
- function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override;
- function GetOutputBufferSize(InputSize: integer): integer; override;
- function GetRatio(): double; override;
- end;
- {$ENDIF}
-
- {$IFDEF UseSRCResample}
- TAudioConverter_SRC = class(TAudioConverter)
- private
- ConverterState: PSRC_STATE;
- ConversionData: SRC_DATA;
- FormatConverter: TAudioConverter;
- public
- function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override;
- destructor Destroy(); override;
-
- function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override;
- function GetOutputBufferSize(InputSize: integer): integer; override;
- function GetRatio(): double; override;
- end;
-
- // Note: SRC (=libsamplerate) provides several converters with different quality
- // speed trade-offs. The SINC-types are slow but offer best quality.
- // The SRC_SINC_* converters are too slow for realtime conversion,
- // (SRC_SINC_FASTEST is approx. ten times slower than SRC_LINEAR) resulting
- // in audible clicks and pops.
- // SRC_LINEAR is very fast and should have a better quality than SRC_ZERO_ORDER_HOLD
- // because it interpolates the samples. Normal "non-audiophile" users should not
- // be able to hear a difference between the SINC_* ones and LINEAR. Especially
- // if people sing along with the song.
- // But FFmpeg might offer a better quality/speed ratio than SRC_LINEAR.
- const
- SRC_CONVERTER_TYPE = SRC_LINEAR;
- {$ENDIF}
-
implementation
{ TAudioConverter_SDL }
@@ -255,272 +206,6 @@ begin
Result := cvt.len_cvt;
end;
-
-{$IFDEF UseFFmpegResample}
-
-const
-{$IFDEF MSWINDOWS}
- ffmpegPlugin = 'ffmpeg_playback.dll';
-{$ENDIF}
-{$IFDEF LINUX}
- ffmpegPlugin = 'ffmpeg_playback';
-{$ENDIF}
-{$IFDEF DARWIN}
- ffmpegPlugin = 'ffmpeg_playback.dylib';
- {$linklib ffmpegPlugin}
-{$ENDIF}
-
-function Plugin_register(core: PMediaPluginCore): PMediaPluginInfo;
- cdecl; external ffmpegPlugin;
-
-function TAudioConverterPlugin.Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean;
-var
- CSrcFormatInfo: TCAudioFormatInfo;
- CDstFormatInfo: TCAudioFormatInfo;
-begin
- inherited Init(SrcFormatInfo, DstFormatInfo);
-
- Result := false;
- fPluginInfo := Plugin_register(MediaPluginCore);
- fPluginInfo.initialize();
- fAudioConverter := fPluginInfo.audioConverter;
-
- AudioFormatInfoToCStruct(SrcFormatInfo, CSrcFormatInfo);
- AudioFormatInfoToCStruct(DstFormatInfo, CDstFormatInfo);
- fStream := fAudioConverter.open(@CSrcFormatInfo, @CDstFormatInfo);
- if (fStream = nil) then
- begin
- Log.LogError('fAudioConverter.open() failed', 'TAudioConverterPlugin.Init');
- Exit;
- end;
-
- Result := true;
-end;
-
-destructor TAudioConverterPlugin.Destroy();
-begin
- if (fStream <> nil) then
- fAudioConverter.close(fStream);
- inherited;
-end;
-
-function TAudioConverterPlugin.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer;
-begin
- Result := fAudioConverter.convert(fStream,
- PCuint8(InputBuffer), PCuint8(OutputBuffer), @InputSize);
-end;
-
-function TAudioConverterPlugin.GetOutputBufferSize(InputSize: integer): integer;
-begin
- Result := fAudioConverter.getOutputBufferSize(fStream, InputSize);
-end;
-
-function TAudioConverterPlugin.GetRatio(): double;
-begin
- Result := fAudioConverter.getRatio(fStream);
-end;
-
-{$ENDIF}
-
-
-{$IFDEF UseSRCResample}
-
-function TAudioConverter_SRC.Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean;
-var
- error: integer;
- TempSrcFormatInfo: TAudioFormatInfo;
- TempDstFormatInfo: TAudioFormatInfo;
-begin
- inherited Init(SrcFormatInfo, DstFormatInfo);
-
- Result := false;
-
- FormatConverter := nil;
-
- // SRC does not handle channel or format conversion
- if ((SrcFormatInfo.Channels <> DstFormatInfo.Channels) or
- not (SrcFormatInfo.Format in [asfS16, asfFloat])) then
- begin
- // SDL can not convert to float, so we have to convert to SInt16 first
- TempSrcFormatInfo := TAudioFormatInfo.Create(
- SrcFormatInfo.Channels, SrcFormatInfo.SampleRate, SrcFormatInfo.Format);
- TempDstFormatInfo := TAudioFormatInfo.Create(
- DstFormatInfo.Channels, SrcFormatInfo.SampleRate, asfS16);
-
- // init format/channel conversion
- FormatConverter := TAudioConverter_SDL.Create();
- if (not FormatConverter.Init(TempSrcFormatInfo, TempDstFormatInfo)) then
- begin
- Log.LogError('Unsupported input format', 'TAudioConverter_SRC.Init');
- FormatConverter.Free;
- // exit after the format-info is freed
- end;
-
- // this info was copied so we do not need it anymore
- TempSrcFormatInfo.Free;
- TempDstFormatInfo.Free;
-
- // leave if the format is not supported
- if (not assigned(FormatConverter)) then
- Exit;
-
- // adjust our copy of the input audio-format for SRC conversion
- Self.SrcFormatInfo.Channels := DstFormatInfo.Channels;
- Self.SrcFormatInfo.Format := asfS16;
- end;
-
- if ((DstFormatInfo.Format <> asfS16) and
- (DstFormatInfo.Format <> asfFloat)) then
- begin
- Log.LogError('Unsupported output format', 'TAudioConverter_SRC.Init');
- Exit;
- end;
-
- ConversionData.src_ratio := DstFormatInfo.SampleRate / SrcFormatInfo.SampleRate;
- if (src_is_valid_ratio(ConversionData.src_ratio) = 0) then
- begin
- Log.LogError('Invalid samplerate ratio', 'TAudioConverter_SRC.Init');
- Exit;
- end;
-
- ConverterState := src_new(SRC_CONVERTER_TYPE, DstFormatInfo.Channels, @error);
- if (ConverterState = nil) then
- begin
- Log.LogError('src_new() failed: ' + src_strerror(error), 'TAudioConverter_SRC.Init');
- Exit;
- end;
-
- Result := true;
-end;
-
-destructor TAudioConverter_SRC.Destroy();
-begin
- if (ConverterState <> nil) then
- src_delete(ConverterState);
- FormatConverter.Free;
- inherited;
-end;
-
-function TAudioConverter_SRC.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer;
-var
- FloatInputBuffer: PSingle;
- FloatOutputBuffer: PSingle;
- TempBuffer: PByteArray;
- TempSize: integer;
- NumSamples: integer;
- OutputSize: integer;
- error: integer;
-begin
- Result := -1;
-
- TempBuffer := nil;
-
- // format conversion with external converter (to correct number of channels and format)
- if (assigned(FormatConverter)) then
- begin
- TempSize := FormatConverter.GetOutputBufferSize(InputSize);
- GetMem(TempBuffer, TempSize);
- InputSize := FormatConverter.Convert(InputBuffer, TempBuffer, InputSize);
- InputBuffer := TempBuffer;
- end;
-
- if (InputSize <= 0) then
- begin
- // avoid div-by-zero problems
- if (InputSize = 0) then
- Result := 0;
- if (TempBuffer <> nil) then
- FreeMem(TempBuffer);
- Exit;
- end;
-
- if (SrcFormatInfo.Format = asfFloat) then
- begin
- FloatInputBuffer := PSingle(InputBuffer);
- end else begin
- NumSamples := InputSize div AudioSampleSize[SrcFormatInfo.Format];
- GetMem(FloatInputBuffer, NumSamples * SizeOf(Single));
- src_short_to_float_array(PCshort(InputBuffer), PCfloat(FloatInputBuffer), NumSamples);
- end;
-
- // calculate approx. output size
- OutputSize := Ceil(InputSize * ConversionData.src_ratio);
-
- if (DstFormatInfo.Format = asfFloat) then
- begin
- FloatOutputBuffer := PSingle(OutputBuffer);
- end else begin
- NumSamples := OutputSize div AudioSampleSize[DstFormatInfo.Format];
- GetMem(FloatOutputBuffer, NumSamples * SizeOf(Single));
- end;
-
- with ConversionData do
- begin
- data_in := PCFloat(FloatInputBuffer);
- input_frames := InputSize div SrcFormatInfo.FrameSize;
- data_out := PCFloat(FloatOutputBuffer);
- output_frames := OutputSize div DstFormatInfo.FrameSize;
- // TODO: set this to 1 at end of file-playback
- end_of_input := 0;
- end;
-
- error := src_process(ConverterState, @ConversionData);
- if (error <> 0) then
- begin
- Log.LogError(src_strerror(error), 'TAudioConverter_SRC.Convert');
- if (SrcFormatInfo.Format <> asfFloat) then
- FreeMem(FloatInputBuffer);
- if (DstFormatInfo.Format <> asfFloat) then
- FreeMem(FloatOutputBuffer);
- if (TempBuffer <> nil) then
- FreeMem(TempBuffer);
- Exit;
- end;
-
- if (SrcFormatInfo.Format <> asfFloat) then
- FreeMem(FloatInputBuffer);
-
- if (DstFormatInfo.Format <> asfFloat) then
- begin
- NumSamples := ConversionData.output_frames_gen * DstFormatInfo.Channels;
- src_float_to_short_array(PCfloat(FloatOutputBuffer), PCshort(OutputBuffer), NumSamples);
- FreeMem(FloatOutputBuffer);
- end;
-
- // free format conversion buffer if used
- if (TempBuffer <> nil) then
- FreeMem(TempBuffer);
-
- if (assigned(FormatConverter)) then
- InputSize := ConversionData.input_frames_used * FormatConverter.SrcFormatInfo.FrameSize
- else
- InputSize := ConversionData.input_frames_used * SrcFormatInfo.FrameSize;
-
- // set result to output size according to SRC
- Result := ConversionData.output_frames_gen * DstFormatInfo.FrameSize;
-end;
-
-function TAudioConverter_SRC.GetOutputBufferSize(InputSize: integer): integer;
-begin
- Result := Ceil(InputSize * GetRatio());
-end;
-
-function TAudioConverter_SRC.GetRatio(): double;
-begin
- // if we need additional channel/format conversion, use this ratio
- if (assigned(FormatConverter)) then
- Result := FormatConverter.GetRatio()
- else
- Result := 1.0;
-
- // now the SRC ratio (Note: the format might change from SInt16 to float)
- Result := Result *
- ConversionData.src_ratio *
- (DstFormatInfo.FrameSize / SrcFormatInfo.FrameSize);
-end;
-
-{$ENDIF}
-
initialization
MediaManager.add(TAudioConverter_SDL.Create);
diff --git a/mediaplugin/src/media/UMediaPlugin.pas b/mediaplugin/src/media/UMediaPlugin.pas
index 762b5af0..bf921423 100644
--- a/mediaplugin/src/media/UMediaPlugin.pas
+++ b/mediaplugin/src/media/UMediaPlugin.pas
@@ -161,6 +161,7 @@ uses
UPathUtils,
ULog,
UAudioDecoderPlugin,
+ UAudioConverterPlugin,
UVideoDecoderPlugin;
var
@@ -397,10 +398,10 @@ begin
// register modules
if (PluginInfo.audioDecoder <> nil) then
MediaManager.Add(TAudioDecoderPlugin.Create(PluginInfo));
+ if (PluginInfo.audioConverter <> nil) then
+ MediaManager.Add(TAudioConverterPlugin.Create(PluginInfo));
if (PluginInfo.videoDecoder <> nil) then
MediaManager.Add(TVideoDecoderPlugin.Create(PluginInfo));
- //if (PluginInfo.audioConverter <> nil) then
- // MediaManager.Add();
end;
end;
diff --git a/mediaplugin/src/ultrastardx.dpr b/mediaplugin/src/ultrastardx.dpr
index 26ff65d5..e5922a65 100644
--- a/mediaplugin/src/ultrastardx.dpr
+++ b/mediaplugin/src/ultrastardx.dpr
@@ -245,7 +245,6 @@ uses
UFFT in 'lib\fft\UFFT.pas',
UAudioPlayback_SoftMixer in 'media\UAudioPlayback_SoftMixer.pas',
{$IFEND}
- UAudioConverter in 'media\UAudioConverter.pas',
//******************************
//Pluggable media modules
@@ -256,6 +255,7 @@ uses
UMediaPlugin in 'media\UMediaPlugin.pas',
UVideoDecoderPlugin in 'media\UVideoDecoderPlugin.pas',
UAudioDecoderPlugin in 'media\UAudioDecoderPlugin.pas',
+ UAudioConverterPlugin in 'media\UAudioConverterPlugin.pas',
UVideo in 'media\UVideo.pas',
@@ -282,6 +282,11 @@ uses
{$IFDEF UsePortaudioPlayback}
UAudioPlayback_Portaudio in 'media\UAudioPlayback_Portaudio.pas',
{$ENDIF}
+ UAudioConverter in 'media\UAudioConverter.pas',
+// TODO
+{$IFDEF UseSRCResample}
+ //UAudioConverter_SRC in 'media\UAudioConverter_SRC.pas',
+{$ENDIF}
// fallback dummy, must be last
UMedia_dummy in 'media\UMedia_dummy.pas',