#include "stdafx.h"

#include "UI.h"

//#include <malloc.h>

#include <stdio.h>

#ifdef _MSVC_INTEL
#pragma warning(disable:4201) // non-standard construct
#include <mmsystem.h>
#pragma warning(default:4201)
#endif

#include "Objects.h"
#include "Dispatch.h"
#include "CSB.h"
#include "Data.h"

//extern i8 data001f2a[];
//extern i8 data001f2c[];
//extern i8 data001f2e[];
//extern i8 data001f32[];
//extern i8 data001f76[];
//extern i8 data002036[];

extern i32 NoSpeedLimit;
extern i32 VBLMultiplier;

struct SNDHEAD
{
  i8  byte0[4];           //"RIFF"
  i32 Size;               //  6076  // #bytes after this integer
  i8  byte8[8];           //"WAVEfmt "
  i32 int16;              //    18
  i16 wFormatTag;         //     1
  i16 nChannels;          //     1
  i32 nSamplesPerSecond;  // 11025
  i32 nAvgBytesPerSec;    // 11025 // important
  i16 nBlockAlign;        //     1 // 2 for 16-bit
  i16 wBitsPerSample;     //     8
  i16 cbSize;             //    40
  i8  byte38[4];          // "fact"
  i32 int42;              //     4
  i32 numBytes46;         //
  i8  byte50[4];          // "data"
  i32 numSamples54;       //
  i8  sample58[1];
};



ui8 ChannelA, ChannelB, ChannelC;

i16 SampleCount  = 0;  //001f2a = 0; // sample count??
i16 SampleRepeat = 0;  //001f2c // repeat count for this sample??
pnt SamplePointer=NULL;//001f2e // nibble address??
                       // 2 * <byte address> + <nibble>
pnt pnt001f32=NULL;  // Points to 2036 or 1f76
i8 data001f36[] ={0x00, //1f36 // Wavetable??
                  0x08, //1f3a // 16 values
                  0x0a, //1f3e // 1f36 followed by 1f76
                  0x0b, //1f42 //  followed by 1fb6.
                  0x0c, //1f46 // register 8 - value
                  0x0d, //1f4a // register 9 - value
                  0x0d, //1f4e // register a - value
                  0x0d, //1f52
                  0x0e, //1f56
                  0x0e, //1f5a
                  0x0e, //1f5e
                  0x0e, //1f62
                  0x0f, //1f66
                  0x0e, //1f6a
                  0x0e, //1f6e
                  0x0e};//1f72
i8 data001f76[] ={0x00,
                  0x05,
                  0x07,
                  0x09,
                  0x09,
                  0x05,
                  0x0a,
                  0x0c,
                  0x08,
                  0x0a,
                  0x0c,
                  0x0d,
                  0x0b,
                  0x0e,
                  0x0e,
                  0x0e};
i8 data001fb6[] ={0x00,
                  0x00,
                  0x00,
                  0x00,
                  0x00,
                  0x00,
                  0x06,
                  0x00,
                  0x00,
                  0x0a,
                  0x0a,
                  0x0a,
                  0x00,
                  0x0b,
                  0x0d,
                  0x0e};
i8 data001ff6[] ={0x00,
                  0x05,
                  0x07,
                  0x08,
                  0x09,
                  0x09,
                  0x0a,
                  0x0a,
                  0x0b,
                  0x0b,
                  0x0b,
                  0x0b,
                  0x0c,
                  0x0c,
                  0x0c,
                  0x0c};
i8 data002036[] ={0x00,
                  0x00,
                  0x01,
                  0x02,
                  0x02,
                  0x05,
                  0x02,
                  0x06,
                  0x03,
                  0x06,
                  0x07,
                  0x08,
                  0x04,
                  0x06,
                  0x08,
                  0x09};
i8 data002076[] ={0x00,
                  0x00,
                  0x00,
                  0x00,
                  0x00,
                  0x02,
                  0x02,
                  0x01,
                  0x01,
                  0x02,
                  0x04,
                  0x05,
                  0x01,
                  0x02,
                  0x00,
                  0x00};

//*********************************************************
// Turn an atari graphic sound into a .wav file.
//*********************************************************
char *SoundDecode(pnt pGraphic, i32 numSample, i32 volume)
{ // volume = 0 is soft
  char *pN;
  FILE *f=NULL;
  unsigned char *pW;
  SNDHEAD *WavBuf;
  i32 i, n, repeat, sample, nibble;
  bool even;
#ifdef _SNDDEBUG
  static bool snddebug = true;
  if(snddebug) f=CREATE("snddbg.txt","w");
  snddebug = false;
#endif
  WavBuf = (SNDHEAD *)UI_malloc(numSample + 58);
  if (WavBuf == NULL) die (0,"No Memory");
  pW = (unsigned char *)WavBuf + 58;
  n = numSample; // Number of samples to store
  pN = pGraphic;
  if (f) fprintf(f,"Starting pN = %08x   Number of samples=%08x\n"
                 ,pN, n);
  even=true;
  while (n > 0)
  {
    if (even)
    {
      sample = *pN & 0xf0;
      if (f) fprintf(f,"Even sample %d\n",sample);
      even = false;
    }
    else
    {
      sample = (*(pN++) << 4) & 0xf0;
      if (f) fprintf(f,"Odd sample %d\n",sample);
      even = true;
    };
    if (sample != 0)
    {
      if (f)
      {
        fprintf(f,"Non-zero sample  n=%d\n",n);
        fprintf(f,"***DEBUG store sample #%d\n",pW-(ui8*)WavBuf-58);
      };
      *(pW++) = (ui8)((sample-0x80)/volume + 0x80);
      n--;
    }
    else
    {
      repeat = 0;
      for (;;)
      {
        if (even)
        {
          nibble = (*pN)>>4;
          if(f) fprintf(f,"Even nibble = %d\n",nibble);
          even=false;
        }
        else
        {
          nibble = *(pN++);
          if(f) fprintf(f,"Odd nibble = %d\n",nibble);
          even = true;
        };
        repeat = (repeat << 3) | (nibble & 7);
        if (f) fprintf(f,"Repeat = %d\n",repeat);
        if ((nibble & 8) == 0) break;
      };
      n -= repeat+3;
      ASSERT(n>=0);
      sample = *(pW-1);
      if(f) fprintf(f,"Sample=%d, repeat=%d,n=%d\n",sample,repeat,n);
      for (i=0; i<repeat+3; i++)
      {
        if (f)
        {
          fprintf(f,"***DEBUG store sample #%d\n",pW-(ui8 *)WavBuf-58);
        };
        *(pW++) = (ui8)sample;
      };
    };
  };
  if(f)
  {
    for (pnt kk=pGraphic; kk<pN+1; kk+=8)
    {
      fprintf(f,"%08x ",kk-pGraphic);
      for (int kkk=0; kkk<8; kkk++)
      {
        fprintf(f,"%02x ", (*(kk+kkk))&0xff);
      };
      fprintf(f,"\n");
    };
    fprintf(f,"Ending pN = %08x\n", pN);
    fclose(f);
    f=NULL;
  };
  ASSERT(n>=0);
  memcpy(WavBuf->byte0,"RIFF",4);
  WavBuf->Size = numSample+58-4;
  memcpy(WavBuf->byte8,"WAVEfmt ",8);
  WavBuf->int16 = 18; // ????
  WavBuf->wFormatTag = 1;
  WavBuf->nChannels = 1;
  WavBuf->nSamplesPerSecond = 6000;
  WavBuf->nAvgBytesPerSec = 6000;
  WavBuf->nBlockAlign = 1;
  WavBuf->wBitsPerSample = 8;
  WavBuf->cbSize = 40;
  memcpy(WavBuf->byte38,"fact",4);
  WavBuf->int42 = 4;
  WavBuf->numBytes46 = numSample;
  memcpy(WavBuf->byte50,"data",4);
  WavBuf->numSamples54 = numSample;
  return (pnt)WavBuf;
}

// Made this a class so the destructor will
// clean things up when we stop the program.
class SOUNDER
{
  char *Wave;
public:
  SOUNDER(void) {Wave=NULL;};
  ~SOUNDER(void)
  {
    if (Wave != NULL)
    {
#ifdef _LINUX
  LIN_KillSound(Wave);
#else
      UI_PlaySound(NULL, SOUND_SYNC|SOUND_MEMORY);
      UI_free (Wave);
#endif
    };
  };
  void Sound(char *wave)
  {
    // We free wave.  Therefore you better not use
    // it again after you call us to play it!
    ASSERT(Wave != wave);
    if (VBLMultiplier != 1) return;
    if (Wave != NULL)
    {
#ifdef _LINUX
    LIN_KillSound(Wave);
#else
      UI_PlaySound(NULL, SOUND_SYNC|SOUND_MEMORY);
      UI_free (Wave);
#endif
    };
    Wave = wave;
#ifdef _LINUX
  LIN_PlaySound(Wave + 58,((SNDHEAD*)Wave)->Size - 58+4, SDL_MIX_MAXVOLUME);
#else
    UI_PlaySound(Wave, SOUND_ASYNC|SOUND_MEMORY);
#endif
  };
};

SOUNDER sounder;

//*********************************************************
//
//*********************************************************
//   TAG001d16
void StartSound(pnt SoundBytes,
                i32 /*timerData*/,
                i32 highVolume)
{
  i32 size, volume;
  static char *Wave = NULL;
  if (NoSound) return;
  size = LE16(wordGear(SoundBytes));
  volume = 1;
  if (highVolume==0) volume = 8;// divisor
  Wave = SoundDecode(SoundBytes+2, size, volume);
  sounder.Sound(Wave);
}




//*********************************************************
//
//*********************************************************
void TAG001e16(i16 P1)
{
  dReg D6, D7;
  aReg A0, A1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //i32 saveD6=D6,saveD7=D7;
  D7W = P1;
  D6L = (i32)dosound(NULL);
  D7L = (D7L & 0xf) * 4;
  A1 = (pnt)0x00ff8800;
  A0 = (pnt)data001f76;
  dosound((pnt)D6L);
  //D6=saveD6;D7=saveD7;
}
/*
//*********************************************************
// This appears to be the interrupt routine to handle
// sound timer interrupts.  I think it operates at
// about 8 KHz.
//*********************************************************
void TAG001e50(void)
{
  dReg D6, D7;
  pnt pD7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //A0 = &data001f2a; // Sound Sample count??
  if (SampleCount != 0)
  {
    SampleCount--;
    //A0 = &data001f2c; // Sample repeat count??
//    A0 = &data001f2e; // Next nibble address
    if (SampleRepeat != 0) // Sample repeat count??
    {
      //A0 = &data001f2c;
      SampleRepeat--;
      return;
    };
    pD7 = SamplePointer;
    SamplePointer++;
    //A0 = &data001f32;
    if (((i32)pD7 & 1) == 0)
    {
      pD7 = (pnt)((i32)pD7 >> 1);
      D7B = (i8)((*pD7 >> 4) & 0x0f); // 4 * Upper nibble
      if (D7B == 0) goto tag001ede;
      //A1 = 0xffff8800;
      //A0 = data001f32;
      //longGear(A1) = longGear(A0+D7W-64); //Channel A
      //longGear(A1) = longGear(A0+D7W+0);  //Channel B
      //longGear(A1) = longGear(A0+D7W+64); //Channel C
      //return;
    }
    else
    {
      D7B = (i8)((*pD7)&15);
      if (D7B ==0) goto tag001ede;
      //D7B <<= 4; // 4 * Lower Nibble
      //A1 = 0xffff8800;
      //A0 = data001f32;
      //longGear(A1) = longGear(A0+D7W-64);
      //longGear(A1) = longGear(A0+D7W+0);
      //longGear(A1) = longGear(A0+D7W+64);
      //return;
    };
    //A1 = 0xffff8800;
    //A0 = data001f32;
    //longGear(A1) = longGear(A0+D7W-64);
    //longGear(A1) = longGear(A0+D7W+0);
    //longGear(A1) = longGear(A0+D7W+64);
    ChannelA = pnt001f32[D7W-16];
    ChannelB = pnt001f32[D7W+00];
    ChannelC = pnt001f32[D7W+16];
    return;
  };
  return;
tag001ede: // Come here when sample value is zero. (D7B)
  D6W = 0;
  for (;;)
  {
    //A0 = data001f2e;
    pD7 = SamplePointer;
    SamplePointer++;
    if (((i32)pD7 & 1) == 0)
    {
      pD7 = (pnt)((i32)pD7 >> 1); // The pointer part of the longword.
//
      D7B = (i8)(*pD7 >> 4); // upper nibble
      //D7B >>= 4;
    }
    else
    {
      pD7 = (pnt)((i32)pD7 >> 1);
      D7B = *pD7; // lower nibble
    };
    if ((D7B & 8) == 0) break;
    D6W = (i16)((D6W << 3) + (D7W & 7));
  };
  D6W = (i16)((D6W << 3) + (D7W & 7) + 2);
  //A0 = data001f2c;
  SampleRepeat = D6W;
  //AllowInterrupts
}
*/
/*
void playSound(i32 soundNum)
{
  ui32 size;
  static SNDHEAD *soundData;
  FILE *sndFile;
  sndFile = UI_fopen("socko.wav", "rb");
  if (sndFile==NULL) return;
  fseek(sndFile,0,SEEK_END);
  size = ftell(sndFile);
  fseek(sndFile,0,SEEK_SET);
  soundData = (SNDHEAD *)UI_malloc(size);
  if (size != fread(soundData,1,size,sndFile)) return;
  //soundData->SamplesPerSecond24 = 6000;
  //soundData->SamplesPerSecond28 = 6000;
  soundData->numSamples54 *= 2;
  soundData->nAvgBytesPerSec *= 2;
  soundData->numBytes46 *= 2;
  soundData->nBlockAlign = 2;
  soundData->wBitsPerSample *= 2;
  //sndPlaySound((char *)soundData,SND_SYNC|SND_MEMORY);
  if (soundNum==0) return;
  //if (soundNum==112)PlaySound("ugh.wav",NULL,SND_ASYNC);
  //if (soundNum==546)PlaySound("socko.wav",NULL,SND_ASYNC);
}

*/



/*
Playing WAVE Resources
You can use the PlaySound function to play a sound that is stored as a
resource. Although this is also possible using the sndPlaySound function,
sndPlaySound requires that you find, load, lock, unlock, and free the
resource; PlaySound achieves all of this with a single line of code.

PlaySound Example
PlaySound("SoundName", hInst, SND_RESOURCE | SND_ASYNC);

sndPlaySound Example
The SND_MEMORY flag indicates that the lpszSoundName parameter is a
pointer to an in-memory image of the WAVE file. To include a WAVE file as
a resource in an application, add the following entry to the application's
resource script (.RC) file.

soundName WAVE c:\sounds\bells.wav

The name soundName is a placeholder for a name that you supply to refer
to this WAVE resource. WAVE resources are loaded and accessed just like
other application-defined Windows resources. The PlayResource function
in the following example plays a specified WAVE resource.

BOOL PlayResource(LPSTR lpName)
{
    BOOL bRtn;
    LPSTR lpRes;
    HANDLE hResInfo, hRes;

    // Find the WAVE resource.

    hResInfo = FindResource(hInst, lpName, "WAVE");
    if (hResInfo == NULL)
        return FALSE;

    // Load the WAVE resource.

    hRes = LoadResource(hInst, hResInfo);
    if (hRes == NULL)
        return FALSE;

    // Lock the WAVE resource and play it.

    lpRes = LockResource(hRes);
    if (lpRes != NULL) {
        bRtn = sndPlaySound(lpRes, SND_MEMORY | SND_SYNC |
            SND_NODEFAULT);
        UnlockResource(hRes);
    }
    else
        bRtn = 0;

    // Free the WAVE resource and return success or failure.

    FreeResource(hRes);
    return bRtn;
}

To play a WAVE resource by using this function, pass to the function a
pointer to a string containing the name of the resource, as shown in
the following example.

PlayResource("soundName");

 */
