DEADSOFTWARE

sdlmixer: more midi configuration
[d2df-sdl.git] / src / engine / e_sound_sdl.inc
index 78214e8c8a51f3b20b3bd2ace5c1003ea06ffd08..f71805ef50324de7d8d9b171871d7a783605753a 100644 (file)
@@ -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
 interface
 
 uses
-  sdl2,
-  SDL2_mixer,
   {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
-  e_log,
-  SysUtils;
+  {$IFDEF USE_SDL}
+    SDL, SDL_mixer,
+    {$DEFINE SDL1MIXER}
+    {$UNDEF  SDL2MIXER}
+  {$ELSE}
+    SDL2, SDL2_mixer,
+    {$UNDEF  SDL1MIXER}
+    {$DEFINE SDL2MIXER}
+  {$ENDIF}
+  envvars, e_log, SysUtils;
 
 type
   TSoundRec = record
@@ -28,6 +33,7 @@ type
     Sound: PMix_Chunk;
     Music: PMix_Music;
     isMusic: Boolean;
+    Loops: Boolean;
     nRefs: Integer;
   end;
 
@@ -71,8 +77,8 @@ const
 
 function e_InitSoundSystem(NoOutput: Boolean = False): Boolean;
 
-function e_LoadSound(FileName: string; var ID: DWORD; isMusic: Boolean): Boolean;
-function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
+function e_LoadSound(FileName: string; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
+function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
 
 // returns channel number or -1
 function e_PlaySound(ID: DWORD): Integer;
@@ -92,10 +98,12 @@ procedure e_SoundUpdate();
 var
   e_SoundsArray: array of TSoundRec = nil;
 
+  e_TimidityDecoder: Boolean; (* sdl_mixer special *)
+
 implementation
 
 uses
-  g_window, g_options, BinEditor;
+  g_window, g_options;
 
 const
   N_CHANNELS = 512;
@@ -118,7 +126,7 @@ var
 
 procedure chanFinished (chan: Integer); cdecl;
 begin
-  //e_WriteLog(Format('chanFinished: %d', [chan]), MSG_NOTIFY);
+  //e_WriteLog(Format('chanFinished: %d', [chan]), TMsgType.Notify);
   if (chan >= 0) and (chan < N_CHANNELS) then
   begin
     if ChanSIds[chan].id <> NO_SOUND_ID then
@@ -137,33 +145,33 @@ procedure dumpMusicType (ms: PMix_Music);
 begin
   if ms = nil then
   begin
-    e_WriteLog('MUSIC FORMAT: NONE', MSG_NOTIFY);
+    e_WriteLog('MUSIC FORMAT: NONE', TMsgType.Notify);
   end
   else
   begin
     case Mix_GetMusicType(ms^) of
       TMix_MusicType.MUS_NONE:
-        e_WriteLog('MUSIC FORMAT: NONE', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: NONE', TMsgType.Notify);
       TMix_MusicType.MUS_CMD:
-        e_WriteLog('MUSIC FORMAT: CMD', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: CMD', TMsgType.Notify);
       TMix_MusicType.MUS_WAV:
-        e_WriteLog('MUSIC FORMAT: WAV', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: WAV', TMsgType.Notify);
       TMix_MusicType.MUS_MOD:
-        e_WriteLog('MUSIC FORMAT: MOD', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: MOD', TMsgType.Notify);
       TMix_MusicType.MUS_MID:
-        e_WriteLog('MUSIC FORMAT: MID', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: MID', TMsgType.Notify);
       TMix_MusicType.MUS_OGG:
-        e_WriteLog('MUSIC FORMAT: OGG', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: OGG', TMsgType.Notify);
       TMix_MusicType.MUS_MP3:
-        e_WriteLog('MUSIC FORMAT: MP3', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: MP3', TMsgType.Notify);
       TMix_MusicType.MUS_MP3_MAD:
-        e_WriteLog('MUSIC FORMAT: MP3_MAD', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: MP3_MAD', TMsgType.Notify);
       TMix_MusicType.MUS_FLAC:
-        e_WriteLog('MUSIC FORMAT: FLAC', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: FLAC', TMsgType.Notify);
       TMix_MusicType.MUS_MODPLUG:
-        e_WriteLog('MUSIC FORMAT: MODPLUG', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: MODPLUG', TMsgType.Notify);
       otherwise
-        e_WriteLog('MUSIC FORMAT: UNKNOWN', MSG_NOTIFY);
+        e_WriteLog('MUSIC FORMAT: UNKNOWN', TMsgType.Notify);
     end;
   end;
 end;
@@ -174,46 +182,63 @@ var
   rfreq: Integer;
   rformat: UInt16;
   rchans: Integer;
+  flags: Integer;
 begin
   if SoundInitialized then begin Result := true; Exit end;
 
   Result := False;
   SoundInitialized := False;
 
+  {$IFDEF HEADLESS}
+    // HACK: shit this into env and hope for the best
+    SetEnvVar('SDL_AUDIODRIVER', 'dummy');
+  {$ENDIF}
+
   if NoOutput then begin Result := true; Exit end;
 
   // wow, this is actually MIDI player!
   // we need module player
-  res := Mix_Init(MIX_INIT_FLAC or MIX_INIT_MOD or MIX_INIT_MODPLUG or MIX_INIT_MP3 or MIX_INIT_OGG or MIX_INIT_FLUIDSYNTH);
-  e_WriteLog(Format('SDL: res=0x%x', [res]), MSG_NOTIFY);
-  if (res and MIX_INIT_FLAC) <> 0 then e_WriteLog('SDL: FLAC playback is active', MSG_NOTIFY);
-  if (res and MIX_INIT_MOD) <> 0 then e_WriteLog('SDL: MOD playback is active', MSG_NOTIFY);
-  if (res and MIX_INIT_MODPLUG) <> 0 then e_WriteLog('SDL: MODPLUG playback is active', MSG_NOTIFY);
-  if (res and MIX_INIT_MP3) <> 0 then e_WriteLog('SDL: MP3 playback is active', MSG_NOTIFY);
-  if (res and MIX_INIT_OGG) <> 0 then e_WriteLog('SDL: OGG playback is active', MSG_NOTIFY);
-  if (res and MIX_INIT_FLUIDSYNTH) <> 0 then e_WriteLog('SDL: FLUIDSYNTH playback is active', MSG_NOTIFY);
-
-  e_WriteLog(Format('SDL: initializing mixer at %d with buffer %d', [gsSDLSampleRate, gsSDLBufferSize]), MSG_NOTIFY);
-  res := Mix_OpenAudio(gsSDLSampleRate, AUDIO_S16LSB, 2, gsSDLBufferSize);
+  flags := MIX_INIT_FLAC or MIX_INIT_MOD or MIX_INIT_MP3 or MIX_INIT_OGG or MIX_INIT_FLUIDSYNTH;
+  {$IFDEF SDL2MIXER}
+    flags := flags or MIX_INIT_MODPLUG;
+  {$ENDIF}
+  res := Mix_Init(flags);
+  e_WriteLog(Format('SDL: res=0x%x', [res]), TMsgType.Notify);
+  if (res and MIX_INIT_FLAC) <> 0 then e_WriteLog('SDL: FLAC playback is active', TMsgType.Notify);
+  if (res and MIX_INIT_MOD) <> 0 then e_WriteLog('SDL: MOD playback is active', TMsgType.Notify);
+  {$IFDEF SDL2MIXER}
+    if (res and MIX_INIT_MODPLUG) <> 0 then e_WriteLog('SDL: MODPLUG playback is active', TMsgType.Notify);
+  {$ENDIF}
+  if (res and MIX_INIT_MP3) <> 0 then e_WriteLog('SDL: MP3 playback is active', TMsgType.Notify);
+  if (res and MIX_INIT_OGG) <> 0 then e_WriteLog('SDL: OGG playback is active', TMsgType.Notify);
+  if (res and MIX_INIT_FLUIDSYNTH) <> 0 then e_WriteLog('SDL: FLUIDSYNTH playback is active', TMsgType.Notify);
+
+  e_WriteLog(Format('SDL: initializing mixer at %d with buffer %d', [gsSDLSampleRate, gsSDLBufferSize]), TMsgType.Notify);
+  res := Mix_OpenAudio(gsSDLSampleRate, MIX_DEFAULT_FORMAT, 2, gsSDLBufferSize);
   if res = -1 then
   begin
-    e_WriteLog('Error initializing SDL mixer:', MSG_FATALERROR);
-    e_WriteLog(Mix_GetError(), MSG_FATALERROR);
+    e_WriteLog('Error initializing SDL mixer:', TMsgType.Fatal);
+    e_WriteLog(Mix_GetError(), TMsgType.Fatal);
     Exit;
   end;
 
   if Mix_QuerySpec(@rfreq, @rformat, @rchans) > 0 then
   begin
-    e_WriteLog(Format('SDL: frequency=%d; format=%u; channels=%d', [rfreq, rformat, rchans]), MSG_NOTIFY);
+    e_WriteLog(Format('SDL: frequency=%d; format=%u; channels=%d', [rfreq, rformat, rchans]), TMsgType.Notify);
   end;
 
   for i := 0 to Mix_GetNumChunkDecoders()-1 do
   begin
-    e_WriteLog(Format('SDL: chunk decoder %s is avalable', [Mix_GetChunkDecoder(i)]), MSG_NOTIFY);
+    e_WriteLog(Format('SDL: chunk decoder %s is avalable', [Mix_GetChunkDecoder(i)]), TMsgType.Notify);
   end;
+
+  e_TimidityDecoder := false;
   for i := 0 to Mix_GetNumMusicDecoders()-1 do
   begin
-    e_WriteLog(Format('SDL: music decoder %s is avalable', [Mix_GetMusicDecoder(i)]), MSG_NOTIFY);
+    case AnsiString(Mix_GetMusicDecoder(i)) of
+      'TIMIDITY': e_TimidityDecoder := true;
+    end;
+    e_WriteLog(Format('SDL: music decoder %s is avalable', [Mix_GetMusicDecoder(i)]), TMsgType.Notify);
   end;
 
   Mix_AllocateChannels(N_CHANNELS);
@@ -283,7 +308,7 @@ begin
   end;
 end;
 
-function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean): Boolean;
+function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
 var
   find_id: DWORD;
 begin
@@ -291,13 +316,13 @@ begin
   Result := False;
   if not SoundInitialized then Exit;
 
-  if isMusic then e_WriteLog('Loading music '+FileName+'...', MSG_NOTIFY)
-  else e_WriteLog('Loading sound '+FileName+'...', MSG_NOTIFY);
+  if isMusic then e_WriteLog('Loading music '+FileName+'...', TMsgType.Notify)
+  else e_WriteLog('Loading sound '+FileName+'...', TMsgType.Notify);
 
   {
   if isMusic then
   begin
-    e_WriteLog('IGNORING MUSIC FROM FILE', MSG_WARNING);
+    e_WriteLog('IGNORING MUSIC FROM FILE', TMsgType.Warning);
     Exit;
   end;
   }
@@ -306,16 +331,17 @@ begin
 
   e_SoundsArray[find_id].Data := nil;
   e_SoundsArray[find_id].isMusic := isMusic;
+  e_SoundsArray[find_id].Loops := isMusic and not ForceNoLoop;
   e_SoundsArray[find_id].nRefs := 0;
 
   if isMusic then
   begin
-    e_WriteLog(Format('  MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
+    e_WriteLog(Format('  MUSIC SLOT: %u', [find_id]), TMsgType.Notify);
     e_SoundsArray[find_id].Music := Mix_LoadMUS(PAnsiChar(FileName));
     if e_SoundsArray[find_id].Music = nil then
     begin
-      e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
-      e_WriteLog(Mix_GetError(), MSG_WARNING);
+      e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), TMsgType.Warning);
+      e_WriteLog(Mix_GetError(), TMsgType.Warning);
       Exit;
     end;
     dumpMusicType(e_SoundsArray[find_id].Music);
@@ -331,7 +357,7 @@ begin
   Result := True;
 end;
 
-function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
+function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
 var
   find_id: DWORD;
   rw: PSDL_RWops;
@@ -346,7 +372,7 @@ begin
   {
   if isMusic then
   begin
-    e_WriteLog('IGNORING MUSIC FROM MEMORY', MSG_WARNING);
+    e_WriteLog('IGNORING MUSIC FROM MEMORY', TMsgType.Warning);
     Exit;
   end;
   }
@@ -360,7 +386,7 @@ begin
     Inc(pc, $400);
     pData := Pointer(pc);
     Dec(Length, $400);
-    e_WriteLog('MUSIC: MP3 ID3 WORKAROUND APPLIED!', MSG_WARNING);
+    e_WriteLog('MUSIC: MP3 ID3 WORKAROUND APPLIED!', TMsgType.Warning);
   end;
   }
 
@@ -372,16 +398,21 @@ begin
   e_SoundsArray[find_id].Data := pData;
   if isid3 then e_SoundsArray[find_id].Data := nil;
   e_SoundsArray[find_id].isMusic := isMusic;
+  e_SoundsArray[find_id].Loops := isMusic and not ForceNoLoop;
   e_SoundsArray[find_id].nRefs := 0;
 
   if isMusic then
   begin
-    e_WriteLog(Format('  MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
-    e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw, 0);
+    e_WriteLog(Format('  MUSIC SLOT: %u', [find_id]), TMsgType.Notify);
+    {$IFDEF SDL1MIXER}
+      e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw);
+    {$ELSE}
+      e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw, 0);
+    {$ENDIF}
     if e_SoundsArray[find_id].Music = nil then
     begin
-      e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
-      e_WriteLog(Mix_GetError(), MSG_WARNING);
+      e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), TMsgType.Warning);
+      e_WriteLog(Mix_GetError(), TMsgType.Warning);
     end
     else
     begin
@@ -416,6 +447,7 @@ end;
 function e_PlaySound (ID: DWORD): Integer;
 var
   res: Integer = -1;
+  loops: Integer = 0;
 begin
   Result := -1;
   if not SoundInitialized then Exit;
@@ -424,7 +456,8 @@ begin
   begin
     if e_SoundsArray[ID].nRefs >= gMaxSimSounds then Exit;
     Inc(e_SoundsArray[ID].nRefs);
-    res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
+    if e_SoundsArray[ID].Loops then loops := -1;
+    res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, loops);
     if res >= 0 then
     begin
       ChanSIds[res].id := ID;
@@ -442,7 +475,8 @@ begin
   begin
     if not e_isMusic(ID) then Exit;
     Mix_HaltMusic();
-    res := Mix_PlayMusic(e_SoundsArray[ID].Music, -1);
+    if e_SoundsArray[ID].Loops then loops := -1;
+    res := Mix_PlayMusic(e_SoundsArray[ID].Music, loops);
     if res >= 0 then res := N_MUSCHAN;
     if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
     Result := res;
@@ -575,7 +609,7 @@ begin
     end;
     if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
     ChanSIds[i].oldvol := trunc(vol*MIX_MAX_VOLUME);
-    //if i = 0 then e_WriteLog(Format('modifying volumes: vol=%f; newvol=%d', [vol, ChanSIds[i].oldvol]), MSG_WARNING);
+    //if i = 0 then e_WriteLog(Format('modifying volumes: vol=%f; newvol=%d', [vol, ChanSIds[i].oldvol]), TMsgType.Warning);
     if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
   end;
   ovol := Mix_VolumeMusic(-1);
@@ -607,11 +641,11 @@ begin
     if ChanSIds[i].muted <> SoundMuted then
     begin
       ChanSIds[i].muted := SoundMuted;
-      //e_WriteLog(Format('gmuting sound for channel %d', [i]), MSG_WARNING);
+      //e_WriteLog(Format('gmuting sound for channel %d', [i]), TMsgType.Warning);
       if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
     end;
   end;
-  //if SoundMuted then e_WriteLog('muting music', MSG_NOTIFY) else e_WriteLog(Format('unmuting music (%d)', [MusVolume]), MSG_NOTIFY);
+  //if SoundMuted then e_WriteLog('muting music', TMsgType.Notify) else e_WriteLog(Format('unmuting music (%d)', [MusVolume]), TMsgType.Notify);
   if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
 end;
 
@@ -698,7 +732,7 @@ begin
   if (FID = NO_SOUND_ID) or not SoundInitialized then Exit;
   FChanNum := e_PlaySoundPanVolume(FID, Pan, Volume);
   Result := (FChanNum >= 0);
-  //if e_isMusic(FID) then e_WriteLog(Format('playing music (%u)', [FID]), MSG_NOTIFY);
+  //if e_isMusic(FID) then e_WriteLog(Format('playing music (%u)', [FID]), TMsgType.Notify);
   //TODO: aPos
 end;
 
@@ -720,15 +754,15 @@ begin
   Result := False;
   if e_isSound(FID) then
   begin
-    //e_WriteLog(Format('IsPlaying: FID=%u; FChanNum=%d', [FID, FChanNum]), MSG_WARNING);
+    //e_WriteLog(Format('IsPlaying: FID=%u; FChanNum=%d', [FID, FChanNum]), TMsgType.Warning);
     chan := Channel;
     if chan < 0 then
     begin
-      //e_WriteLog(Format('IsPlaying: FID=%u; ONA', [FID]), MSG_WARNING);
+      //e_WriteLog(Format('IsPlaying: FID=%u; ONA', [FID]), TMsgType.Warning);
       Exit;
     end;
     //Result := (Mix_Playing(chan) > 0)
-    //e_WriteLog(Format('IsPlaying: FID=%u; TAN', [FID]), MSG_WARNING);
+    //e_WriteLog(Format('IsPlaying: FID=%u; TAN', [FID]), TMsgType.Warning);
     Result := True;
   end
   else if e_isMusic(FID) then
@@ -834,12 +868,12 @@ begin
   begin
     chan := Channel;
     if chan < 0 then Exit;
-    //e_WriteLog(Format('SetVolume: chan=%d; Volume=%f', [chan, Volume]), MSG_WARNING);
+    //e_WriteLog(Format('SetVolume: chan=%d; Volume=%f', [chan, Volume]), TMsgType.Warning);
     e_chanSetVol(chan, Volume);
   end
   else if e_isMusic(FID) then
   begin
-    //e_WriteLog(Format('SetVolume: chan=MUSIC; Volume=%f', [Volume]), MSG_WARNING);
+    //e_WriteLog(Format('SetVolume: chan=MUSIC; Volume=%f', [Volume]), TMsgType.Warning);
     e_chanSetVol(N_MUSCHAN, Volume);
   end;
 end;
@@ -896,7 +930,7 @@ begin
     if chan < 0 then Exit;
     if ChanSIds[chan].muted <> Enable then
     begin
-      //e_WriteLog(Format('muting sound for channel %d', [cnan]), MSG_WARNING);
+      //e_WriteLog(Format('muting sound for channel %d', [cnan]), TMsgType.Warning);
       ChanSIds[chan].muted := Enable;
       if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, ChanSIds[chan].oldvol);
     end;