DEADSOFTWARE

al: fix build with sdl 1.2
[d2df-sdl.git] / src / engine / e_soundfile_wav.pas
index 340aa920725f1cd69dca7054f4f70acd3c152eb2..153cad427f4f1b58c94f60977644c9dedeb882ec 100644 (file)
@@ -24,15 +24,17 @@ type
 
   TWAVLoader = class (TSoundLoader)
   public
-    function Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean; override; overload;
-    function Load(FName: string; SStreaming: Boolean): Boolean; override; overload;
-    function SetPosition(Pos: LongWord): Boolean; 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;
-    function GetAll(var OutPtr: Pointer): LongWord; override;
     procedure Free(); override;
   private
     FData: Pointer;
     FDataLen: LongWord;
+    FDataPos: LongWord;
+    FLooping: Boolean;
   end;
 
   TWAVLoaderFactory = class (TSoundLoaderFactory)
@@ -46,7 +48,7 @@ implementation
 
 uses
   {$IFDEF USE_SDL}
-    SDL,
+    SDL, cmem,
   {$ELSE}
     SDL2,
   {$ENDIF}
@@ -79,34 +81,35 @@ begin
 end;
 
 (* TWAVLoader *)
-function FixSoundEndian (Buf: PUInt8; Len: UInt32; format: UInt16; rate: cint; chan: UInt8): Boolean;
-  const
-    {$IFDEF FPC_LITTLE_ENDIAN}
-      TARGET_AUDIO_S16 = AUDIO_S16LSB;
-      TARGET_AUDIO_U16 = AUDIO_U16LSB;
-    {$ELSE}
-      TARGET_AUDIO_S16 = AUDIO_S16MSB;
-      TARGET_AUDIO_U16 = AUDIO_U16MSB;
-    {$ENDIF}
+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_U16LSB, AUDIO_U16MSB: tformat := TARGET_AUDIO_U16;
-    AUDIO_S16LSB, AUDIO_S16MSB: tformat := TARGET_AUDIO_S16;
-  else tformat := format
+    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;
-  Result := True;
-  if format <> tformat then
+  if (result = true) and (format <> tformat) then
   begin
     Result := False;
     if SDL_BuildAudioCVT(@cvt, format, chan, rate, tformat, chan, rate) <> -1 then
     begin
-      cvt.buf := Buf;
-      cvt.len := Len;
-      assert(cvt.len_mult = 1);
-      Result := SDL_ConvertAudio(@cvt) = 0;
-      assert(cvt.len_ratio = 1);
-      assert(cvt.len = Len)
+      {$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;
@@ -124,7 +127,7 @@ begin
   if SDL_LoadWAV_RW(RW, 0, @Spec, PUInt8(@Buf), @Len) <> nil then
 {$ENDIF}
   begin
-    Result := FixSoundEndian(Buf, Len, Spec.format, Spec.freq, Spec.channels);
+    Result := ConvertSound(Buf, Len, Spec.format, Spec.freq, Spec.channels);
     if Result = True then
     begin
       with Loader do
@@ -136,7 +139,7 @@ begin
           FFormat.SampleBits := Spec.format and $FF;
         {$ENDIF}
         FFormat.Channels := Spec.channels;
-        FStreaming := False; // never stream wavs
+        FDataPos := 0;
         FDataLen := Len;
         FData := Buf;
       end
@@ -148,7 +151,7 @@ begin
   end
 end;
 
-function TWAVLoader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean;
+function TWAVLoader.Load(Data: Pointer; Len: LongWord; Loop: Boolean): Boolean;
   var
     RW: PSDL_RWops;
 begin
@@ -157,9 +160,11 @@ begin
   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; SStreaming: Boolean): Boolean;
+function TWAVLoader.Load(FName: string; Loop: Boolean): Boolean;
   var
     RW: PSDL_RWops;
 begin
@@ -176,36 +181,50 @@ begin
     Result := False
   end;
   SDL_RWclose(RW);
+  FStreaming := False;
+  FLooping := Loop;
 end;
 
-function TWAVLoader.SetPosition(Pos: LongWord): Boolean;
+function TWAVLoader.Finished(): Boolean;
 begin
-  Result := False; // makes no sense when not streaming
+  Result := FDataPos >= FDataLen;
 end;
 
-function TWAVLoader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord;
+function TWAVLoader.Restart(): Boolean;
 begin
-  if FDataLen < Len then
-    Len := FDataLen;
-  if FData <> nil then
-  begin
-    Move(FData^, Buf^, Len);
-    Result := Len;
-  end
-  else
-    Result := 0;
+  Result := True;
+  FDataPos := 0;
 end;
 
-function TWAVLoader.GetAll(var OutPtr: Pointer): LongWord;
+function TWAVLoader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord;
+var
+  OutPos: LongWord;
+  Tx: LongWord;
 begin
-  OutPtr := FData;
-  Result := FDataLen;
+  OutPos := 0;
+  Result := 0;
+
+  while (FDataPos < FDataLen) and (OutPos < Len) do
+  begin
+    Tx := nmin(FDataLen - FDataPos, Len - OutPos);
+    Move((FData + FDataPos)^, (Buf + OutPos)^, Tx);
+
+    FDataPos := FDataPos + Tx;
+    OutPos := OutPos + Tx;
+    Result := Result + Tx;
+
+    if (FDataPos >= FDataLen) and FLooping then
+      FDataPos := 0;
+  end;
 end;
 
 procedure TWAVLoader.Free();
 begin
   if FData <> nil then
     SDL_FreeWAV(FData); // SDL allocates inside the DLL, so we need this
+  FDataPos := 0;
+  FData := nil;
+  FDataLen := 0;
 end;
 
 initialization