X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fengine%2Fe_soundfile_wav.pas;h=153cad427f4f1b58c94f60977644c9dedeb882ec;hb=f2b9872b69cf016222f45b3a6261116d9f23f4ff;hp=b88dd5a8dfc784f70bd4e0255a5e31e8af7b5604;hpb=b6261de6b40b4b79207cc01889b94e3237e1bba6;p=d2df-sdl.git diff --git a/src/engine/e_soundfile_wav.pas b/src/engine/e_soundfile_wav.pas index b88dd5a..153cad4 100644 --- a/src/engine/e_soundfile_wav.pas +++ b/src/engine/e_soundfile_wav.pas @@ -2,8 +2,7 @@ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,20 +21,42 @@ uses e_soundfile; type // a WAV loader that just uses SDL_LoadWAV + TWAVLoader = class (TSoundLoader) public - function CanLoad(Data: Pointer; Len: Integer): Boolean; override; overload; - function CanLoad(FName: string): Boolean; override; overload; - function Load(Data: Pointer; Len: Integer; var OutLen: Integer; var OutFmt: TSoundFormat): Pointer; override; overload; - function Load(FName: string; var OutLen: Integer; var OutFmt: TSoundFormat): Pointer; override; overload; - procedure Free(Data: Pointer); override; + function Load(Data: Pointer; Len: LongWord; Loop: Boolean): Boolean; override; overload; + function Load(FName: string; Loop: Boolean): Boolean; override; overload; + function Finished(): Boolean; override; + function Restart(): Boolean; override; + function FillBuffer(Buf: Pointer; Len: LongWord): LongWord; override; + procedure Free(); override; + private + FData: Pointer; + FDataLen: LongWord; + FDataPos: LongWord; + FLooping: Boolean; + end; + + TWAVLoaderFactory = class (TSoundLoaderFactory) + public + function MatchHeader(Data: Pointer; Len: LongWord): Boolean; override; + function MatchExtension(FName: string): Boolean; override; + function GetLoader(): TSoundLoader; override; end; implementation -uses sdl2, utils, e_log; +uses + {$IFDEF USE_SDL} + SDL, cmem, + {$ELSE} + SDL2, + {$ENDIF} + utils, ctypes, e_log; + +(* TWAVLoaderFactory *) -function TWAVLoader.CanLoad(Data: Pointer; Len: Integer): Boolean; +function TWAVLoaderFactory.MatchHeader(Data: Pointer; Len: LongWord): Boolean; var P: PByte; begin @@ -48,80 +69,164 @@ begin Result := ((P+0)^ = Ord('R')) and ((P+1)^ = Ord('I')) and ((P+2)^ = Ord('F')) and ((P+3)^ = Ord('F')); end; -function TWAVLoader.CanLoad(FName: string): Boolean; +function TWAVLoaderFactory.MatchExtension(FName: string): Boolean; begin - // TODO: actually check for RIFF header + // TODO: ehhh Result := GetFilenameExt(FName) = '.wav'; end; -function TWAVLoader.Load(Data: Pointer; Len: Integer; var OutLen: Integer; var OutFmt: TSoundFormat): Pointer; -var - Spec: TSDL_AudioSpec; - RW: PSDL_RWops; - TmpLen: UInt32; - TmpBuf: PUInt8; +function TWAVLoaderFactory.GetLoader(): TSoundLoader; begin - Result := nil; + Result := TWAVLoader.Create(); +end; - RW := SDL_RWFromConstMem(Data, Len); +(* TWAVLoader *) +function ConvertSound (var buf: PUInt8; var len: UInt32; var format: UInt16; rate: cint; chan: UInt8): Boolean; + var cvt: TSDL_AudioCVT; tformat: UInt16; +begin + result := true; + case format of + AUDIO_U8, AUDIO_S8 : tformat := AUDIO_U8; (* yes, unsigned *) + AUDIO_U16LSB, AUDIO_U16MSB: tformat := AUDIO_S16SYS; (* and yes, signed *) + AUDIO_S16LSB, AUDIO_S16MSB: tformat := AUDIO_S16SYS; + {$IFDEF USE_SDL2} + AUDIO_S32LSB, AUDIO_S32MSB: tformat := AUDIO_S16SYS; (* 32bit not supported in al core *) + AUDIO_F32LSB, AUDIO_F32MSB: tformat := AUDIO_S16SYS; (* float not supported in al core *) + {$ENDIF} + else result := false (* unsupported format *) + end; + if (result = true) and (format <> tformat) then + begin + Result := False; + if SDL_BuildAudioCVT(@cvt, format, chan, rate, tformat, chan, rate) <> -1 then + begin + {$IFDEF USE_SDL2} + buf := SDL_realloc(buf, len * cvt.len_mult); + {$ELSE} + buf := realloc(buf, len * cvt.len_mult); + {$ENDIF} + cvt.len := len; + cvt.buf := buf; + result := SDL_ConvertAudio(@cvt) = 0; + len := cvt.len_cvt; + format := tformat + end + end +end; - if SDL_LoadWAV_RW(RW, 0, @Spec, @TmpBuf, @TmpLen) = nil then +function LoadWavRW (Loader: TWAVLoader; RW: PSDL_RWops): Boolean; + var + Spec: TSDL_AudioSpec; + Len: UInt32; + Buf: PUInt8; +begin + Result := False; +{$IFDEF USE_SDL2} + if SDL_LoadWAV_RW(RW, 0, @Spec, @Buf, @Len) <> nil then +{$ELSE} + if SDL_LoadWAV_RW(RW, 0, @Spec, PUInt8(@Buf), @Len) <> nil then +{$ENDIF} begin + Result := ConvertSound(Buf, Len, Spec.format, Spec.freq, Spec.channels); + if Result = True then + begin + with Loader do + begin + FFormat.SampleRate := Spec.freq; + {$IFDEF USE_SDL2} + FFormat.SampleBits := SDL_AUDIO_BITSIZE(Spec.format); + {$ELSE} + FFormat.SampleBits := Spec.format and $FF; + {$ENDIF} + FFormat.Channels := Spec.channels; + FDataPos := 0; + FDataLen := Len; + FData := Buf; + end + end + else + begin + SDL_FreeWav(Buf) + end + end +end; + +function TWAVLoader.Load(Data: Pointer; Len: LongWord; Loop: Boolean): Boolean; + var + RW: PSDL_RWops; +begin + RW := SDL_RWFromConstMem(Data, Len); + Result := LoadWavRW(Self, RW); + if Result = False then e_LogWriteln('Could not load WAV: ' + SDL_GetError()); + SDL_RWclose(RW); + FStreaming := False; + FLooping := Loop; +end; + +function TWAVLoader.Load(FName: string; Loop: Boolean): Boolean; + var + RW: PSDL_RWops; +begin + RW := SDL_RWFromFile(PChar(FName), 'rb'); + if RW <> nil then + begin + Result := LoadWavRW(Self, RW); + if Result = False then + e_LogWritefln('Could not load WAV file `%s`: %s', [FName, SDL_GetError()]); end else begin - OutFmt.Loader := self; - OutFmt.SampleRate := Spec.freq; - OutFmt.SampleBits := SDL_AUDIO_BITSIZE(Spec.format); - OutFmt.Channels := Spec.channels; - OutLen := TmpLen; - Result := TmpBuf; + e_LogWritefln('Could not open WAV file `%s`: %s', [FName, SDL_GetError()]); + Result := False end; - SDL_RWclose(RW); + FStreaming := False; + FLooping := Loop; end; -function TWAVLoader.Load(FName: string; var OutLen: Integer; var OutFmt: TSoundFormat): Pointer; -var - Spec: TSDL_AudioSpec; - RW: PSDL_RWops; - TmpLen: UInt32; - TmpBuf: PUInt8; +function TWAVLoader.Finished(): Boolean; begin - Result := nil; + Result := FDataPos >= FDataLen; +end; - RW := SDL_RWFromFile(PChar(FName), 'rb'); +function TWAVLoader.Restart(): Boolean; +begin + Result := True; + FDataPos := 0; +end; - if RW = nil then - begin - e_LogWritefln('Could not open WAV file `%s`: %s', [FName, SDL_GetError()]); - exit; - end; +function TWAVLoader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord; +var + OutPos: LongWord; + Tx: LongWord; +begin + OutPos := 0; + Result := 0; - if SDL_LoadWAV_RW(RW, 0, @Spec, @TmpBuf, @TmpLen) = nil then + while (FDataPos < FDataLen) and (OutPos < Len) do begin - e_LogWritefln('Could not load WAV file `%s`: %s', [FName, SDL_GetError()]); - Result := nil; - end - else - begin - OutFmt.Loader := self; - OutFmt.SampleRate := Spec.freq; - OutFmt.SampleBits := SDL_AUDIO_BITSIZE(Spec.format); - OutFmt.Channels := Spec.channels; - OutLen := TmpLen; - Result := TmpBuf; - end; + Tx := nmin(FDataLen - FDataPos, Len - OutPos); + Move((FData + FDataPos)^, (Buf + OutPos)^, Tx); - SDL_RWclose(RW); + FDataPos := FDataPos + Tx; + OutPos := OutPos + Tx; + Result := Result + Tx; + + if (FDataPos >= FDataLen) and FLooping then + FDataPos := 0; + end; end; -procedure TWAVLoader.Free(Data: Pointer); +procedure TWAVLoader.Free(); begin - SDL_FreeWAV(Data); // SDL allocates inside the DLL, so we need this + if FData <> nil then + SDL_FreeWAV(FData); // SDL allocates inside the DLL, so we need this + FDataPos := 0; + FData := nil; + FDataLen := 0; end; initialization - e_AddSoundLoader(TWAVLoader.Create()); + e_AddSoundLoader(TWAVLoaderFactory.Create()); end.