
//
// Strife's I_StartSound:
//
int __fastcall I_StartSound(int id, void *data, int vol, int sep, int pitch)
{
  int result; // eax@3

  if ( snd_SfxDevice != 1 || data != (void *)S_sfx[5].data )
    result = SFX_PlayPatch(data, sep, pitch, vol, 0, 100);
  else
    result = -1;
  return result;
}

//
// DMX::SFX_PlayPatch
//
// Note that the API of this function changed between v1.2 and v1.666 of DOOM.
// That would be around the time that Paul Radek broke pitch shifting and GUS support,
// prompting Romero's famous disparaging comments toward him...
// Strife is based on DOOM v1.666 so we can assume the pitch support is broken here
//
int __fastcall SFX_PlayPatch(void *data, int sep, int pitch, int vol, int zero, int hundred)
{
  int result; // eax@1
  int v7; // edi@1
  void *dataptr; // esi@1
  int v9; // edx@2
  int v10; // [sp+0h] [bp-10h]@2

  dataptr = data;
  v7 = sep;
  result = -1;
  if ( dataptr )
  {
    LOWORD(sep) = *(_WORD *)dataptr; // First byte of the sfx data is the format (01, 02, or 03)
    v10 = sep;
    if ( (_WORD)sep < 1u )
    {
      if ( !(_WORD)v9 )
        result = sub_4BD70();
    }
    else
    {
      if ( (_WORD)v9 <= 2u )
      {
        result = sub_4C260(hundred);
      }
      else
      {
        if ( (_WORD)v9 == 3 ) // Format 3 == Digital SFX
          result = sub_48430(dataptr, v7, pitch, vol, zero, hundred);
      }
    }
    if ( result >= 0 )
      result |= (unsigned __int16)v10 << 16;
  }
  return result;
}

//
// Some kind of "thunk" or call-through, just calls another routine
//
int __fastcall sub_48430(void *data, int sep, int pitch, int vol, int zero, int hundred)
{
  return sub_4D370(data, sep, pitch, vol, zero, hundred);
}

//
// Sub for the above. Does some kind of preprocessing and then calls the real money
// function below... (sub_4D130)
//
int __fastcall sub_4D370(void *data, int sep, int pitch, int vol, char zero, int hundred)
{
  void *v7; // esi@1
  int v8; // edi@1
  int a3; // [sp+8h] [bp-Ch]@1
  int a4; // [sp+4h] [bp-10h]@1
  int a5; // [sp+0h] [bp-14h]@1

  v7 = data;
  v8 = sep;
  sub_4CE30(/* parameters are unknown! */);
  return sub_4D130(v7, v8, a3, a4, a5, zero, hundred);
}

//
// This is the most problematic routine as the decompilation is a completely unusable mess.
// See the raw assembly code at the bottom.
//
int __fastcall sub_4CE30()
{
  __int64 qax0; // qax@0 - haleyjd: The chance this is really a quad word is pretty much 0 -- Hex-Rays is bad about this.
  int ecx0; // ecx@0
  int ebx0; // ebx@0
  int v3; // edi@1
  signed int v4; // esi@1
  int v5; // edi@2
  signed __int64 v6; // qax@8 - haleyjd: Again, these don't really seem to be quad words, just two DWORDs back to back.
  signed __int64 v7; // qax@9 - haleyjd: idiv and imul instructions tend to confuse Hex-Rays severely.
  int arg0; // [sp+10h] [bp+4h]@0

  v4 = qax0;
  v3 = *((_DWORD *)&qax0 + 1);
  if ( !byte_E0C56 )
  {
    v5 = 2 * *((_DWORD *)&qax0 + 1) + 2;
    *(_DWORD *)ecx0 = v5;
    *((_DWORD *)&qax0 + 1) = arg0;
    *(_DWORD *)ebx0 = v5;
LABEL_10:
    **((_DWORD **)&qax0 + 1) = 0;
    return qax0;
  }
  if ( (_DWORD)qax0 < 0 )
    v4 = 0;
  if ( v4 > 255 )
    v4 = 255;
  *((_DWORD *)&qax0 + 1) = 255 - v4;
  if ( !dword_9ABEC )
  {
    *((_DWORD *)&v7 + 1) = v3 * byte_9ABF0[*((_DWORD *)&qax0 + 1)];
    *(_DWORD *)ebx0 = (v7 >> 32) / 127;
    *(_DWORD *)&v7 = v3 * byte_9ABF0[v4];
    *((_DWORD *)&v7 + 1) = v3 * byte_9ABF0[v4] >> 31;
    *(_DWORD *)&qax0 = v7 / 127;
    *((_DWORD *)&qax0 + 1) = arg0;
    *(_DWORD *)ecx0 = qax0;
    goto LABEL_10;
  }
  *((_DWORD *)&v6 + 1) = v3 * byte_9ACF0[*((_DWORD *)&qax0 + 1)];
  *(_DWORD *)ebx0 = (v6 >> 32) / 127;
  *(_DWORD *)&v6 = v3 * byte_9ACF0[v4];
  *((_DWORD *)&v6 + 1) = v3 * byte_9ACF0[v4] >> 31; // haleyjd: See? this is because of imul and idiv which use two regs as edx:eax or vice versa...
  *(_DWORD *)&qax0 = v6 / 127;
  *((_DWORD *)&qax0 + 1) = arg0;
  *(_DWORD *)ecx0 = qax0;
  **((_DWORD **)&qax0 + 1) = 16 - ((v4 + 1) >> 3);
  return qax0;
}

//
// Here's the real money! sub_4D130 populates the DMX channel structure after
// finding an appropriate channel for the sound (it appears to base this on
// the pointer, and on a "tag" which is passed in the "hundred" parameter -
// so named because in I_StartSound, "100" is always passed here. Notably,
// I_StartVoice passes a different value, and seemingly as a result, sounds
// played through I_StartVoice exhibit *absolute priority* over those started
// by I_StartSound...
//
// a3, a4, and a5 are likely calculated by the above routine and returned by
// reference through in-params. Their exact purpose is not known yet.
//
/*
 Here is the currently known layout of the DMX channel struct:
 
 00000000 dmxchan_t       struc ; (sizeof=0x26)
 00000000 vol1            dd ?
 00000004 vol2            dd ?
 00000008 a5tsrdiv22050   dd ?
 0000000C sndsamplerate   dw ?
 0000000E lenM32          dd ?
 00000012 data            dd ?
 00000016 unknDword1      dd ?  ; unknown what this means!
 0000001A dmxMixStruct    dd ?  ; pointer to another struct, 36 bytes in size - gets used in lower-level sound blasting routines
 0000001E hundred         dd ?
 00000022 negone          dd ?  ; starts out as -1 at init time, but gets changed by this routine - some kind of status flag maybe??
 00000026 dmxchan_t       ends
*/
int __fastcall sub_4D130(void *data, int sep, int a3, int a4, int a5, char zero, int hundred)
{
  int result; // eax@2
  int v8; // edx@3
  int v9; // edi@3
  int v10; // esi@3
  dmxchan_t *v11; // ebx@4
  int v12; // eax@5
  int v13; // ebp@8
  int v14; // ebx@21
  int v15; // eax@22
  int v16; // eax@27
  dmxchan_t *v17; // ecx@27
  unsigned int v18; // ebx@27
  int v19; // esi@27
  dmxchan_t *v20; // ecx@27
  signed __int64 v21; // qax@27
  int v22; // edx@27
  char v23; // dl@27
  void *v24; // eax@27
  void *v29; // [sp+Ch] [bp-18h]@1
  int v30; // [sp+4h] [bp-20h]@1
  int v31; // [sp+0h] [bp-24h]@1
  int v32; // [sp+8h] [bp-1Ch]@1
  void *v33; // [sp+10h] [bp-14h]@1
  signed int v34; // [sp+14h] [bp-10h]@3

  v29 = data;             // NOTE: v29 is data, from S_sfx[].data
  v30 = sep;
  v31 = a3;
  v32 = a4;
  v33 = data;             // NOTE: v33 is data, from S_sfx[].data
  if ( !dword_9ABD0 )
    return -1;
  v10 = 0;
  v9 = 0;
  v8 = 0;
  v34 = -1;
  if ( dmxNumChannels > 0 ) // dmxNumChannels seems to be either 1 or 8.
  {
    v11 = dmxChannels;
    do
    {
      v12 = v11->dmxMixStruct;
      if ( !*(_DWORD *)(v12 + 8) && !*(_DWORD *)v12 )
      {
        v9 = v8;
        goto LABEL_27;
      }
      v13 = v11->hundred;
      if ( v10 >= v13 )
      {
        if ( v10 != v13 || *(_DWORD *)v12 || *(_DWORD *)(v12 + 8) >= (unsigned int)v34 )
          goto LABEL_15;
        v34 = *(_DWORD *)(v12 + 8);
      }
      else
      {
        v10 = v11->hundred;
      }
      v9 = v8;
LABEL_15:
      ++v8;
      ++v11;
    }
    while ( v8 < dmxNumChannels );
  }
  if ( v10 >= hundred && v10 )
  {
    if ( v10 == hundred )
    {
      if ( v33 != (void *)dmxChannels[v9].data )
      {
        v14 = 0;
        if ( dmxNumChannels > 0 )
        {
          v15 = 0;
          while ( v33 != *(void **)((char *)&dmxChannels[0].data + v15)
               || **(_DWORD **)((char *)&dmxChannels[0].dmxMixStruct + v15) )
          {
            v15 += 38;
            ++v14;
            if ( v15 >= 38 * dmxNumChannels )
              goto LABEL_27;
          }
          v9 = v14;
        }
      }
    }
LABEL_27:
    v20 = &dmxChannels[v9];
    v19 = v20->dmxMixStruct;
    __asm { pushf }
    *(_DWORD *)&v21 = v33;
    v20->data = (int)v33;
    v20->lenM32 = *(_DWORD *)((_DWORD)v21 + 4) - 32; // STORE THE SAMPLE LENGTH (offset 4) MINUS 32 BYTES
    v20->sndsamplerate = *((_WORD *)v33 + 1);
    v20->hundred = hundred;
    v20->negone = (v20->negone + 1) & 0xFF;
    v20->vol1 = v31;
    v22 = (unsigned __int16)dmx_smplrate1;
    v20->vol2 = v32;
    *((_DWORD *)&v21 + 1) = a5 * v22;
    v20->a5tsrdiv22050 = (v21 >> 32) / 22050;        // calculate a5 * dmx_smplrate1 / 22050
    sub_4CDC0(&dmxChannels[v9]);                     // NOTE: This routine may negate a5tsrdiv22050
    memset_((void *)v19, v23, 36);
    *(_DWORD *)(v19 + 12) = v17->unknDword1;
    
    v18 = ((unsigned __int16)(((unsigned __int16)byte_9A9D0[2 * v30] << 8) + (unsigned __int16)byte_9A9D1[2 * v30])
         * (unsigned int)v17->sndsamplerate
         + ((signed int)(unsigned __int16)dmx_smplrate1 >> 1))
        / (unsigned __int16)dmx_smplrate1;
    
    *(_DWORD *)(v19 + 24) = ((unsigned __int16)(((unsigned __int16)byte_9A9D0[2 * v30] << 8)
                                              + (unsigned __int16)byte_9A9D1[2 * v30])
                           * (unsigned int)v17->sndsamplerate
                           + ((signed int)(unsigned __int16)dmx_smplrate1 >> 1))
                          / (unsigned __int16)dmx_smplrate1 & 0xFF;

    *(_DWORD *)(v19 + 20) = ((signed int)(unsigned __int16)v18 >> 8) & 0xFF;
    
    v24 = v29; // NOTE: v24 is now == S_sfx[].data
    
    *(_DWORD *)(v19 + 24) |= *(_DWORD *)(v19 + 24) >> 1 << 8;

    *(_DWORD *)(v19 + 16) = (char *)v24 + 24; // v19+16 = data + 24 !!!!

    // If a5tsrdiv22050 was not negated by sub_4CDC0, the data pointer will be fiddled:
    v16 = v17->a5tsrdiv22050;
    if ( v16 > 0 )
      *(_DWORD *)(v19 + 16) -= v16;
    
    *(_DWORD *)(v19 + 28) = v17->a5tsrdiv22050;
    
    // Now fiddling with the sample length as well, based on len-32 / v18 calc'd above
    *(_DWORD *)(v19 + 8) = (v17->lenM32 << 8) / (unsigned int)(_WORD)v18;
    
    // "zero" is always passed as 0 by the DOOM engine so this does nothing as far as it's concerned
    if ( zero & 1 )
    {
      *(_DWORD *)(v19 + 4) = *(_DWORD *)(v19 + 16);
      *(_DWORD *)v19 = *(_DWORD *)(v19 + 8);
    }
    __asm { popf }
    result = v17->negone + (v9 << 8);
  }
  else
  {
    result = -1;
  }
  return result;
}

// subroutine for the above... unknown purpose

char __fastcall sub_4CDC0(dmxchan_t *chan)
{
  dmxchan_t *v1; // ebx@1

  v1 = chan;
  if ( byte_E0C56 != 1 && byte_E0C56 != 3 )
  {
    if ( byte_E0C56 == 2 )
    {
      sub_4CD50();
    }
    else
    {
      if ( byte_E0C56 )
        return (_BYTE)chan;            // If either of these returns is taken,
    }                                  // the a5 value will *not* be negated.
    LOBYTE(chan->vol1) = sub_4CD50();  //
    return (_BYTE)chan;                //
  }
  sub_4CD50();
  LOBYTE(chan->vol1) = sub_4CD50();
  v1->a5tsrdiv22050 = -v1->a5tsrdiv22050; // Here is where the a5-derived value gets negated...
  return (_BYTE)chan;
}

// Subroutine for the above. Again, unknown purpose.

signed int __fastcall sub_4CD50(int a1, signed int a2)
{
  signed int result; // eax@1
  int v3; // edx@1
  int v4; // ebx@1
  signed int v5; // ebp@1
  signed int v6; // edi@1
  signed int v7; // esi@1
  signed int v8; // edi@1
  signed int v9; // eax@1
  signed int v10; // eax@2
  signed int v11; // ecx@2
  signed int v12; // eax@2
  int v13; // edx@2
  int v14; // ecx@2

  v4 = a1;
  v8 = a2;
  v7 = 0;
  v3 = a2 / -2;
  v9 = v8 >> 8;
  v6 = (_BYTE)v8;
  v5 = v9;
  result = v6 >> 1;
  do
  {
    v10 = v6 + result;
    *(_BYTE *)v4 = v3;
    v7 += 2;
    v11 = v10 >> 8;
    v12 = v6 + (_BYTE)v10;
    v13 = v5 + v11 + v3;
    v4 += 2;
    *(_BYTE *)(v4 - 1) = v13;
    v14 = v5 + (v12 >> 8);
    result = (_BYTE)v12;
    v3 = v14 + v13;
  }
  while ( v7 < 256 );
  return result;
}


// Here is the asm for sub_4CE30:
/*
cseg01:0004CE30 ; int __fastcall sub_4CE30()
cseg01:0004CE30 sub_4CE30       proc near               ; CODE XREF: sub_4D050+18p
cseg01:0004CE30                                         ; sub_4D370+18p
cseg01:0004CE30
cseg01:0004CE30 arg_0           = dword ptr  4
cseg01:0004CE30
cseg01:0004CE30                 push    esi             ; appears to be doing stereo & pitch stuff...
cseg01:0004CE31                 push    edi
cseg01:0004CE32                 push    ebp
cseg01:0004CE33                 mov     esi, eax        ; pitch
cseg01:0004CE35                 mov     edi, edx        ; volume
cseg01:0004CE37                 cmp     byte_E0C56, 0
cseg01:0004CE3E                 jnz     short loc_4CE51
cseg01:0004CE40                 lea     edi, [edx+edx+2]
cseg01:0004CE44                 mov     [ecx], edi      ; volume -> *a4 ?
cseg01:0004CE46                 mov     edx, [esp+0Ch+arg_0]
cseg01:0004CE4A                 mov     [ebx], edi      ; volume -> *a5 ?
cseg01:0004CE4C                 jmp     loc_4CEF0
cseg01:0004CE51 ; ---------------------------------------------------------------------------
cseg01:0004CE51
cseg01:0004CE51 loc_4CE51:                              ; CODE XREF: sub_4CE30+Ej
cseg01:0004CE51                 test    esi, esi
cseg01:0004CE53                 jge     short loc_4CE57
cseg01:0004CE55                 xor     esi, esi
cseg01:0004CE57
cseg01:0004CE57 loc_4CE57:                              ; CODE XREF: sub_4CE30+23j
cseg01:0004CE57                 cmp     esi, 0FFh
cseg01:0004CE5D                 jle     short loc_4CE64
cseg01:0004CE5F                 mov     esi, 0FFh
cseg01:0004CE64
cseg01:0004CE64 loc_4CE64:                              ; CODE XREF: sub_4CE30+2Dj
cseg01:0004CE64                 mov     edx, 0FFh
cseg01:0004CE69                 mov     ebp, dword_9ABEC
cseg01:0004CE6F                 sub     edx, esi
cseg01:0004CE71                 test    ebp, ebp
cseg01:0004CE73                 jz      short loc_4CEBB
cseg01:0004CE75                 mov     dl, byte_9ACF0[edx] ; volume ramp lookup?
cseg01:0004CE7B                 and     edx, 0FFh
cseg01:0004CE81                 imul    edx, edi
cseg01:0004CE84                 mov     ebp, 7Fh ; ''
cseg01:0004CE89                 mov     eax, edx
cseg01:0004CE8B                 sar     edx, 1Fh
cseg01:0004CE8E                 idiv    ebp
cseg01:0004CE90                 xor     edx, edx
cseg01:0004CE92                 mov     [ebx], eax
cseg01:0004CE94                 mov     dl, byte_9ACF0[esi]
cseg01:0004CE9A                 imul    edx, edi
cseg01:0004CE9D                 mov     eax, edx
cseg01:0004CE9F                 sar     edx, 1Fh
cseg01:0004CEA2                 idiv    ebp
cseg01:0004CEA4                 lea     edx, [esi+1]
cseg01:0004CEA7                 mov     ebx, 10h
cseg01:0004CEAC                 sar     edx, 3
cseg01:0004CEAF                 sub     ebx, edx
cseg01:0004CEB1                 mov     edx, [esp+0Ch+arg_0]
cseg01:0004CEB5                 mov     [ecx], eax
cseg01:0004CEB7                 mov     [edx], ebx
cseg01:0004CEB9                 jmp     short loc_4CEF6
cseg01:0004CEBB ; ---------------------------------------------------------------------------
cseg01:0004CEBB
cseg01:0004CEBB loc_4CEBB:                              ; CODE XREF: sub_4CE30+43j
cseg01:0004CEBB                 mov     dl, byte_9ABF0[edx]
cseg01:0004CEC1                 and     edx, 0FFh
cseg01:0004CEC7                 imul    edx, edi
cseg01:0004CECA                 mov     ebp, 7Fh ; ''
cseg01:0004CECF                 mov     eax, edx
cseg01:0004CED1                 sar     edx, 1Fh
cseg01:0004CED4                 idiv    ebp
cseg01:0004CED6                 xor     edx, edx
cseg01:0004CED8                 mov     [ebx], eax
cseg01:0004CEDA                 mov     dl, byte_9ABF0[esi]
cseg01:0004CEE0                 imul    edx, edi
cseg01:0004CEE3                 mov     eax, edx
cseg01:0004CEE5                 sar     edx, 1Fh
cseg01:0004CEE8                 idiv    ebp
cseg01:0004CEEA                 mov     edx, [esp+0Ch+arg_0]
cseg01:0004CEEE                 mov     [ecx], eax
cseg01:0004CEF0
cseg01:0004CEF0 loc_4CEF0:                              ; CODE XREF: sub_4CE30+1Cj
cseg01:0004CEF0                 mov     dword ptr [edx], 0
cseg01:0004CEF6
cseg01:0004CEF6 loc_4CEF6:                              ; CODE XREF: sub_4CE30+89j
cseg01:0004CEF6                 pop     ebp
cseg01:0004CEF7                 pop     edi
cseg01:0004CEF8                 pop     esi
cseg01:0004CEF9                 retn    4
cseg01:0004CEF9 sub_4CE30       endp

*/