Subversion Repositories pentevo

Rev

Rev 883 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "vs1001.h"
  6. #include "bass.h"
  7. #include "snd_bass.h"
  8.  
  9. static bool SkipZeroes = true;
  10.  
  11. void TRingBuffer::Reset()
  12. {
  13.     CritSect.Lock();
  14.     WrPos = RdPos = 0;
  15.     Dreq = true;
  16.     Count = 0;
  17.     Cancelled = false;
  18.     NotEmpty.Reset();
  19.     CritSect.Unlock();
  20. }
  21.  
  22. void TRingBuffer::Put(u8 Val)
  23. {
  24.     CritSect.Lock();
  25.     Buf[WrPos++] = Val;
  26.     WrPos &= (Size - 1);
  27.     Count++;
  28.     assert(Count < Size);
  29.     Dreq = (Size - Count) > 32;
  30.     NotEmpty.Set();
  31.     CritSect.Unlock();
  32. }
  33.  
  34. u32 TRingBuffer::Get(void *Data, u32 ReqLen)
  35. {
  36.     u32 RetLen;
  37.     u8 *Ptr = (u8 *)Data;
  38.  
  39. retry:
  40.     NotEmpty.Wait();
  41.  
  42.     CritSect.Lock();
  43.     if(Count == 0)
  44.     {
  45.         CritSect.Unlock();
  46.         if(Cancelled)
  47.             return 0;
  48.         goto retry;
  49.     }
  50.  
  51.     assert(Count != 0);
  52.  
  53.     if(Cancelled)
  54.     {
  55.         CritSect.Unlock();
  56.         return 0;
  57.     }
  58.  
  59.     RetLen = min(Count, ReqLen);
  60.     if(RetLen)
  61.     {
  62.         u32 RdLen = min(RetLen, Size - RdPos);
  63.         memcpy(Ptr, &Buf[RdPos], RdLen);
  64.         RdPos += RdLen;
  65.         RdPos &= (Size - 1);
  66.         Ptr += RdLen;
  67.         if(RetLen > RdLen)
  68.         {
  69.             assert(RdPos == 0);
  70.             RdLen = RetLen - RdLen;
  71.             memcpy(Ptr, Buf, RdLen);
  72.             RdPos += RdLen;
  73.             RdPos &= (Size - 1);
  74.         }
  75.         Count -= RetLen;
  76.  
  77.         Dreq = (Size - Count) > 32;
  78.  
  79.         if(Count == 0)
  80.             NotEmpty.Reset();
  81.     }
  82.     CritSect.Unlock();
  83.  
  84.     return RetLen;
  85. }
  86.  
  87. BASS_FILEPROCS TVs1001::Procs = { TVs1001::StreamClose, TVs1001::StreamLen, TVs1001::StreamRead, TVs1001::StreamSeek };
  88.  
  89. TVs1001::TVs1001() : EventStreamClose(FALSE)
  90. {
  91.     Mp3Stream = 0;
  92.     ThreadHandle = nullptr;
  93.  
  94.     Regs[VOL] = 0; // max volume on all channels
  95.  
  96.     Reset();
  97.  
  98.     SetVol(Regs[VOL]);
  99. }
  100.  
  101. void TVs1001::Reset()
  102. {
  103. //    printf(__FUNCTION__"\n");
  104.  
  105.     memset(Regs, 0, sizeof(Regs));
  106.  
  107.     CurState = ST_IDLE;
  108.     Idx = 0;
  109.     Msb = Lsb = 0xFF;
  110.     nCs = true;
  111.     RingBuffer.Reset();
  112.  
  113.     if(conf.gs_type != 1)
  114.         return;
  115.  
  116.     if(!BASS::Initialized)
  117.     {
  118.         BASS::Init(-1, conf.sound.fq, BASS_DEVICE_LATENCY, wnd, nullptr);
  119.         ThreadHandle = (HANDLE)_beginthreadex(nullptr, 0, Thread, this, 0, nullptr);
  120.         BASS::Initialized = true;
  121.     }
  122. }
  123.  
  124. void TVs1001::SetNcs(bool nCs)
  125. {
  126.     TVs1001::nCs = nCs;
  127.     if(nCs)
  128.         CurState = ST_IDLE;
  129. }
  130.  
  131. u8 TVs1001::Rd()
  132. {
  133.     if(nCs) // codec not selected
  134.         return 0xFF;
  135.  
  136.     u16 Val = Rd(Idx);
  137.     u8 RetVal = 0xFF;
  138.     TState NextState = CurState;
  139.     switch(CurState)
  140.     {
  141.     case ST_RD_MSB: RetVal = (Val >> 8U) & 0xFF; NextState = ST_RD_LSB; break;
  142.     case ST_RD_LSB: RetVal = Val & 0xFF;  NextState = ST_IDLE; break;
  143.     }
  144. //    printf("Vs1001: RD %s->%s, val = 0x%X\n", State2Str(CurState), State2Str(NextState), RetVal);
  145.     CurState = NextState;
  146.  
  147.     return RetVal;
  148. }
  149.  
  150. u16 TVs1001::Rd(int Idx)
  151. {
  152.     switch(Idx)
  153.     {
  154.     case MODE:
  155.     case CLOCKF:
  156.     case STATUS:
  157.     case AUDATA:
  158.     case HDAT0:
  159.     case HDAT1:
  160.     case AIADDR:
  161.     case VOL:
  162.     case AICTRL0:
  163.     case AICTRL1:
  164.         return Regs[Idx];
  165.     case DECODE_TIME:
  166.         return GetDecodeTime();
  167.     }
  168.     return 0xFFFF;
  169. }
  170.  
  171. void TVs1001::Wr(int Idx, u16 Val)
  172. {
  173.     switch(Idx)
  174.     {
  175.     case CLOCKF:
  176.     case WRAM_W:
  177.     case WRAMADDR_W:
  178.     case AIADDR:
  179.     case AICTRL0:
  180.     case AICTRL1:
  181.         Regs[Idx] = Val;
  182.     break;
  183.  
  184.     case VOL:
  185.         Regs[Idx] = Val;
  186.         SetVol(Val);
  187.     break;
  188.  
  189.     case MODE:
  190.         Regs[Idx] = Val;
  191.         if(Val & SM_RESET)
  192.             SoftReset();
  193.     break;
  194.  
  195.     case STATUS:
  196.         Regs[Idx] = Val & 0xF; // vs1001
  197.     break;
  198.     }
  199. }
  200.  
  201. void TVs1001::WrCmd(u8 Val)
  202. {
  203.     TState NextState = ST_IDLE;
  204.  
  205.     if(nCs) // codec not selected
  206.         return;
  207.  
  208.     switch(CurState)
  209.     {
  210.     case ST_IDLE:
  211.         switch(Val)
  212.         {
  213.         case CMD_RD: NextState = ST_RD_IDX; break;
  214.         case CMD_WR: NextState = ST_WR_IDX; break;
  215.         default:
  216. //            printf("Vs1001: invalid cmd = 0x%X\n", Val);
  217.            ;
  218.         }
  219.     break;
  220.     case ST_RD_IDX: Idx = Val; NextState = ST_RD_MSB; break;
  221.     case ST_WR_IDX: Idx = Val; NextState = ST_WR_MSB; break;
  222.     case ST_WR_MSB: Msb = Val; NextState = ST_WR_LSB; break;
  223.     case ST_WR_LSB:
  224.         Lsb = Val;
  225.         Wr(Idx, u16((Msb << 8U) | Lsb));
  226.     break;
  227.  
  228.     case ST_RD_MSB:
  229.     case ST_RD_LSB:
  230.         NextState = CurState;
  231.     break;
  232.  
  233.     default:
  234. //        printf("Vs1001: WR invalid state = %s\n", State2Str(CurState));
  235.         ;
  236.     }
  237. //    printf("Vs1001: WR %s->%s, val = 0x%X\n", State2Str(CurState), State2Str(NextState), Val);
  238.     CurState = NextState;
  239. }
  240.  
  241. void TVs1001::Wr(u8 Val)
  242. {
  243. //    printf(__FUNCTION__" val = 0x%X\n", Val);
  244.     if(!Mp3Stream && SkipZeroes)
  245.     {
  246.         if(Val == 0) // skip zeroes before format detection
  247.             return;
  248.         SkipZeroes = false;
  249.     }
  250.  
  251.     RingBuffer.Put(Val);
  252. }
  253.  
  254. void TVs1001::SetVol(u16 Vol)
  255. {
  256. //   __debugbreak();
  257.    if(!Mp3Stream)
  258.        return;
  259.  
  260.    float VolDbR = (Vol & 0xFF) / 2.0f;
  261.    float VolDbL = ((Vol >> 8U) & 0xFF) / 2.0f;
  262.    float VolR = powf(10.0f, -VolDbR / 10.0f);
  263.    float VolL = powf(10.0f, -VolDbL / 10.0f);
  264.    float Pan = VolR - VolL;
  265.    float VolM = (VolR + VolL) / 2.0f;
  266.  
  267. //   printf("%s, Vol = %u\n", __FUNCTION__, Vol);
  268.    if (!BASS::ChannelSetAttribute(Mp3Stream, BASS_ATTRIB_VOL, VolM))
  269.        printf("BASS_ChannelSetAttribute() [vol]\n");
  270.    if (!BASS::ChannelSetAttribute(Mp3Stream, BASS_ATTRIB_PAN, Pan))
  271.        printf("BASS_ChannelSetAttribute() [pan]\n");
  272. }
  273.  
  274. u16 TVs1001::GetDecodeTime()
  275. {
  276.     if(!Mp3Stream)
  277.         return 0;
  278.  
  279.     QWORD Pos = BASS::ChannelGetPosition(Mp3Stream, BASS_POS_BYTE);
  280.     double Time = BASS::ChannelBytes2Seconds(Mp3Stream, Pos);
  281.     return (u16)Time;
  282. }
  283.  
  284. // called from main loop when processing ngs z80 code
  285. void TVs1001::SoftReset()
  286. {
  287. //    printf("%s\n", __FUNCTION__);
  288.  
  289.     ShutDown();
  290.  
  291.     if(Mp3Stream)
  292.     {
  293.         if(!BASS::ChannelStop(Mp3Stream))
  294.         {
  295.             printf("BASS_ChannelStop()\n");
  296.             assert(false);
  297.         }
  298.  
  299.         if(!BASS::StreamFree(Mp3Stream))
  300.         {
  301.             printf("BASS_ChannelStop()\n");
  302.             assert(false);
  303.         }
  304.  
  305.         EventStreamClose.Wait();
  306.         EventStreamClose.Reset();
  307.         Mp3Stream = 0;
  308.     }
  309.  
  310.     RingBuffer.Reset();
  311.     SkipZeroes = true;
  312.     ThreadHandle = (HANDLE)_beginthreadex(nullptr, 0, Thread, this, 0, nullptr);
  313. }
  314.  
  315. void TVs1001::ShutDown()
  316. {
  317.     RingBuffer.Cancel();
  318.  
  319.     if(ThreadHandle)
  320.     {
  321.         WaitForSingleObject(ThreadHandle, INFINITE);
  322.         CloseHandle(ThreadHandle);
  323.         ThreadHandle = nullptr;
  324.     }
  325. }
  326.  
  327. // called from main loop priodicaly
  328. void TVs1001::Play()
  329. {
  330.    if(!Mp3Stream)
  331.        return;
  332.  
  333.    BASS::ChannelPlay(Mp3Stream, FALSE);
  334. }
  335.  
  336. // stream file format detection tread
  337. void TVs1001::Thread()
  338. {
  339. //    printf(__FUNCTION__"\n");
  340.     Mp3Stream = BASS::StreamCreateFileUser(STREAMFILE_BUFFER, BASS_SAMPLE_FLOAT | BASS_STREAM_BLOCK, &Procs, this);
  341.     if(!Mp3Stream)
  342.     {
  343. //        printf(__FUNCTION__" Err = %d\n", BASS_ErrorGetCode());
  344.     }
  345. //    printf(__FUNCTION__"->Exit\n");
  346. }
  347.  
  348. // bass asynchronous callback
  349. void TVs1001::StreamClose()
  350. {
  351.     EventStreamClose.Set();
  352. }
  353.  
  354. // bass asynchronous callback
  355. QWORD TVs1001::StreamLen()
  356. {
  357.     return 0;
  358. }
  359.  
  360. // bass asynchronous callback
  361. DWORD TVs1001::StreamRead(void *Buffer, DWORD Length)
  362. {
  363.     DWORD Len = RingBuffer.Get(Buffer, Length);
  364. //    printf(__FUNCTION__"->%d/%d\n", Length, Len);
  365.  
  366. /*
  367.     static FILE *f = fopen("dump.mp3", "wb");
  368.     if(Len != 0)
  369.         fwrite(Buffer, Len, 1, f);
  370. */
  371.     return Len;
  372. }
  373.  
  374. // bass asynchronous callback
  375. BOOL TVs1001::StreamSeek(QWORD offset)
  376. {
  377.     (void)offset;
  378.     return FALSE;
  379. }
  380.  
  381. #define STATE2STR(x) case x:  return #x
  382.  
  383. const char *TVs1001::State2Str(TState State)
  384. {
  385.     switch(State)
  386.     {
  387.     STATE2STR(ST_IDLE);
  388.     STATE2STR(ST_RD);
  389.     STATE2STR(ST_WR);
  390.     STATE2STR(ST_RD_IDX);
  391.     STATE2STR(ST_WR_IDX);
  392.     STATE2STR(ST_RD_MSB);
  393.     STATE2STR(ST_RD_LSB);
  394.     STATE2STR(ST_WR_MSB);
  395.     STATE2STR(ST_WR_LSB);
  396.     }
  397.     return "???";
  398. }
  399.  
  400. TVs1001 Vs1001;
  401.