Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "bass.h"
  6. #include "snd_bass.h"
  7. #include "gshle.h"
  8. #include "gs.h"
  9. #include "sndrender/sndcounter.h"
  10. #include "sound.h"
  11. #include "util.h"
  12.  
  13. #ifdef MOD_GSBASS
  14. void GSHLE::set_busy(unsigned char newval)
  15. {
  16.    busy = chan[0].busy = chan[1].busy = chan[2].busy = chan[3].busy = newval;
  17. }
  18.  
  19. void GSHLE::reset()
  20. {
  21. //    printf("%s, speed=6\n", __FUNCTION__);
  22.    fxvol = modvol = 0x3F;
  23.    speed = 6;
  24.    make_gs_volume(fxvol);
  25.    to_ptr = data_in; mod_playing = 0;
  26.    used = 0; mod = nullptr; modsize = 0; set_busy(0);
  27.    resetmod(); total_fx = 1;
  28.    memset(sample, 0, sizeof sample);
  29.    memset(chan,  0, sizeof chan);
  30.    memset(&DebugCh, 0, sizeof(DebugCh));
  31.    out(0xBB, 0x23); // send 'get pages' command
  32. }
  33.  
  34. void GSHLE::applyconfig()
  35. {
  36.     // ╧хЁхёўхЄ эюЄ т ухЁЎ√ фы  ЁртэюьхЁэю ЄхьяхЁшЁютрээюую ёЄЁю 
  37.     // https://ru.wikipedia.org/wiki/╨ртэюьхЁэю_ЄхьяхЁшЁютрээ√щ_ёЄЁющ
  38.     // f = f0 * 2^(i/12)
  39.     // f0 = 440Hz (A4) - ┴рчютр  ўрёЄюЄр (i=0)
  40.     // ═юЄр | ╚эфхъё ёЄхяхэш | ═юЄр GS
  41.     // -----+----------------+---------
  42.     // C0:  | i=-9-4*12=-57  | 0
  43.     // C1:  | i=-9-3*12=-45  | 12
  44.     // C2:  | i=-9-2*12=-33  | 24
  45.     // C3:  | i=-9-1*12=-21  | 36
  46.     // C4:  | i=-9+0*12=-9   | 48
  47.     // C5:  | i=-9+1*12=3    | 60 // ▌Єющ эюЄх ёююЄтхЄёЄтєхЄ ёЄрэфрЁЄэр  ёъюЁюёЄ№ яЁюшуЁ√трэш  214 яхЁшюфют ухэхЁрЄюЁр эр Amiga
  48.     // C6:  | i=-9+2*12=15   | 72
  49.     // C7:  | i=-9+3*12=27   | 84
  50.  
  51.  
  52.     // ╨рёўхЄ ўрёЄюЄ тёхї эюЄ
  53.     int i;
  54.     for(i = -57; i <= 27; i++)
  55.     {
  56.         note2rate[i + 57] = float(440.0 * pow(2.0, double(i) / 12.0));
  57.     }
  58.     for(; i + 57 < int(_countof(note2rate)); i++)
  59.     {
  60.         note2rate[i + 57] = note2rate[57+27];
  61.     }
  62.  
  63.     const double C5 = double(note2rate[60]);
  64.  
  65.     // ╧ххЁёўхЄ ўрёЄюЄ т sample rate юЄэюёшЄхы№эю ёЄрэфрЁЄэющ эюЄ√ C5 ё шэфхъёюь 60
  66.     for(i = 0; i < int(_countof(note2rate)); i++)
  67.     {
  68.         // 7093789.2 / 2 - clock rate PAL Amiga
  69.         // 214.0 (яхЁшюфют тэєЄЁхээхую ухэхЁрЄюЁр) - ╤3 эр Amiga (ёююЄтхЄёЄтєхЄ C5 эр GS)
  70.         note2rate[i] *= float(7093789.2 / (2.0 * 214.0 * C5));
  71.     }
  72.     setmodvol(modvol);
  73. }
  74.  
  75. unsigned char GSHLE::in(unsigned char port)
  76. {
  77.    if (port == 0xBB) return gsstat;
  78.    if (!resptr) return 0xFF; // no data available
  79.    unsigned char byte = *resptr;
  80.    if(resmode)
  81.    {
  82.        resptr++;
  83.        resmode--;
  84.    } // goto next byte
  85.    return byte;
  86. }
  87.  
  88. void GSHLE::out(unsigned char port, unsigned char byte)
  89. {
  90.    if (port == 0xB3) {
  91.       if (!load_stream) {
  92.          *to_ptr = byte;
  93.          if(resmod2)
  94.          {
  95.              to_ptr++;
  96.              resmod2--;
  97.          }
  98.          if (!resmod2) {
  99.             if ((gscmd & 0xF8) == 0x88) start_fx(data_in[0], gscmd & 3, 0xFF, data_in[1]);
  100.             if ((gscmd & 0xF8) == 0x90) start_fx(data_in[0], gscmd & 3, data_in[1], 0xFF);
  101.             if ((gscmd & 0xF8) == 0x98) start_fx(data_in[0], gscmd & 3, data_in[2], data_in[1]);
  102.             to_ptr = data_in;
  103.          }
  104.       } else {
  105.          if (load_stream == 4) { // covox
  106.             //flush_dig_snd();          //юсэютыхэшх фю чряшёш
  107.             covFB_vol = byte*conf.sound.gs_vol/0x100;
  108.             flush_dig_snd();            //NS FIX?
  109.             return;
  110.          }
  111.          streamstart[streamsize++] = byte;
  112.          if (load_stream == 1) loadmod = 1;
  113.          else loadfx = u8(cur_fx);
  114.       }
  115.       return;
  116.    }
  117.    // else command
  118.    unsigned i;
  119.    gsstat = 0x7E; resmode = 0; // default - 1 byte ready
  120.    resptr = gstmp; to_ptr = data_in; resmod2 = 0;
  121.    gscmd = byte;
  122.    if (load_stream == 4) load_stream = 0; // close covox mode
  123.    switch (byte) {
  124.       case 0x0E: // LPT covox
  125.          load_stream = 4;
  126.          break;
  127.       case 0xF3: case 0xF4: // reset
  128.          reset_gs();
  129.          break;
  130.       case 0xF5:
  131.          set_busy(1); break;
  132.       case 0xF6:
  133.          set_busy(0); break;
  134.       case 0x20: // get total memory
  135.          *(unsigned*)gstmp = conf.gs_ramsize*1024-32768-16384;
  136.          resmode = 2; gsstat = 0xFE;
  137.          break;
  138.       case 0x21: // get free memory
  139.          *(unsigned*)gstmp = (conf.gs_ramsize*1024-32768-16384) - used;
  140.          resmode = 2; gsstat = 0xFE;
  141.          break;
  142.       case 0x23: // get pages
  143.          *gstmp = u8(((conf.gs_ramsize*1024)/32768)-1);
  144.           gsstat = 0xFE;
  145.          break;
  146.       case 0x2A: // set module vol
  147.       case 0x35:
  148.          *gstmp = u8(modvol);
  149.          modvol = *data_in;
  150.          setmodvol(modvol);
  151.          break;
  152.       case 0x2B: // set FX vol
  153.       case 0x3D:
  154.          *gstmp = u8(fxvol);
  155.          fxvol = *data_in;
  156.          make_gs_volume(fxvol);
  157.          break;
  158.       case 0x2E: // set FX
  159.           // printf("%u: %s, set fx = %u\n", unsigned(rdtsc()), __FUNCTION__, *data_in);
  160.           if(*data_in == 0)
  161.           { // COM_H.a80, COM2E
  162.               cur_fx = total_fx - 1;
  163.           }
  164.           else
  165.           {
  166.               if(*data_in > total_fx - 1)
  167.               {
  168.                   cur_fx = 0;
  169.               }
  170.               else
  171.               {
  172.                   cur_fx = *data_in;
  173.               }
  174.           }
  175.          break;
  176.       case 0x30: // load MOD
  177.          resetmod();
  178.          streamstart = mod = GSRAM_M + used;
  179.          streamsize = 0;
  180.          *gstmp = 1; load_stream = 1;
  181.          break;
  182.       case 0x31: // play MOD
  183.          restart_mod(0,0);
  184.          break;
  185.       case 0x32: // stop MOD
  186.          mod_playing = 0;
  187.          stop_mod();
  188.          break;
  189.       case 0x33: // continue MOD
  190.          if (mod)
  191.          {
  192.              mod_playing = 1;
  193.              cont_mod();
  194.          }
  195.          break;
  196.       case 0x36: // data = #FF
  197.          *gstmp = 0xFF;
  198.          break;
  199.       case 0x38: // load FX (unsigned samples)
  200.       case 0x3E: // (signed samples)
  201.           if(total_fx >= 64)
  202.           {
  203.               cur_fx = 0; // COM_H.a80, COM38_9
  204.               break;
  205.           }
  206.          cur_fx = *gstmp = total_fx;
  207.          load_stream = (byte == 0x38) ? 2 : 3;
  208.          streamstart = GSRAM_M + used;
  209.          sample[total_fx].start = streamstart;
  210.          streamsize = 0;
  211.          break;
  212.       case 0x39: // play FX
  213.           // printf("%u: %s, start fx = %u\n", unsigned(rdtsc()), __FUNCTION__, *data_in);
  214.          start_fx(*data_in, 0xFF, 0xFF, 0xFF);
  215.          break;
  216.       case 0x3A: // stop fx
  217.           // printf("%u: %s, stop fx = %u\n", unsigned(rdtsc()), __FUNCTION__, *data_in);
  218.           for(i = 0; i < 4; i++)
  219.           {
  220.               if(*data_in & (1 << i))
  221.               {
  222.                   chan[i].start = nullptr;
  223.               }
  224.           }
  225.          break;
  226.       case 0x40: // set note
  227.           if(cur_fx == 0)
  228.           {
  229.               break;
  230.           }
  231.          sample[cur_fx].note = *data_in <= 95 ? *data_in : 95;
  232.          break;
  233.       case 0x41: // set vol
  234.          sample[cur_fx].volume = *data_in;
  235.          break;
  236.       case 0x42: // Set FX Sample Finetune
  237.           sample[cur_fx].FineTune = *data_in;
  238.           break;
  239.       case 0x45: // set fx priority
  240.           sample[cur_fx].Priority = *data_in;
  241.           break;
  242.       case 0x46: // Set FX Sample Seek First parameter
  243.           sample[cur_fx].SeekFirst = *data_in;
  244.           break;
  245.       case 0x47: // Set FX Sample Seek Last parameter
  246.           sample[cur_fx].SeekLast = *data_in;
  247.           break;
  248.       case 0x48: // set loop start
  249.          resmod2 = 2;
  250.          *(unsigned char*)&sample[cur_fx].loop = *data_in;
  251.          to_ptr = 1+(unsigned char*)&sample[cur_fx].loop;
  252.          break;
  253.       case 0x49: // set loop end
  254.          resmod2 = 2;
  255.          *(unsigned char*)&sample[cur_fx].end = *data_in;
  256.          to_ptr = 1+(unsigned char*)&sample[cur_fx].end;
  257.          break;
  258.       case 0x60: // get song pos
  259.          *gstmp = (unsigned char)modgetpos();
  260.          break;
  261.       case 0x61: // get pattern pos
  262.          *gstmp = (unsigned char)(modgetpos() >> 16);
  263.          break;
  264.       case 0x62: // get mixed pos
  265.          i = modgetpos();
  266.          *gstmp = u8(((i>>16) & 0x3F) | (i << 6));
  267.          break;
  268.       case 0x63: // get module notes
  269.         resmode = 3; gsstat = 0xFE;
  270.         break;
  271.       case 0x64: // get module vols
  272.         *(unsigned*)gstmp = 0;
  273.         resmode = 3; gsstat = 0xFE;
  274.         break;
  275.      case 0x65: // jmp to pos
  276.         restart_mod(*data_in,0);
  277.         break;
  278.      case 0x66: // Set speed/tempo
  279.          if(*data_in <= 0x1F)
  280.          {
  281.              speed = *data_in;
  282.              //printf("%s, speed=%u\n", __FUNCTION__, speed);
  283.              SetModSpeed();
  284.          }
  285.          else
  286.          {
  287.              tempo = *data_in;
  288.          }
  289.          break;
  290.      case 0x67:
  291.          // Get speed value
  292.          *gstmp = speed;
  293.          break;
  294.      case 0x68: // Get tempo value
  295.          *gstmp = tempo;
  296.          break;
  297.      case 0x80: // direct play 1
  298.      case 0x81:
  299.      case 0x82:
  300.      case 0x83:
  301.         start_fx(*data_in, byte & 3, 0xFF, 0xFF);
  302.         break;
  303.      case 0x88: // direct play 2
  304.      case 0x89:
  305.      case 0x8A:
  306.      case 0x8B:
  307.      case 0x90: // direct play 3
  308.      case 0x91:
  309.      case 0x92:
  310.      case 0x93:
  311.         resmod2 = 1; to_ptr++;
  312.         break;
  313.      case 0x98: // direct play 4
  314.      case 0x99:
  315.      case 0x9A:
  316.      case 0x9B:
  317.         resmod2 = 2; to_ptr++;
  318.         break;
  319.  
  320.       case 0xD2: // close stream
  321.          if (!load_stream) break;
  322.          // bug?? command #3E loads unsigned samples (REX 1,2)
  323. //         if (load_stream == 3) // unsigned sample -> convert to unsigned
  324. //            for (unsigned ptr = 0; ptr < streamsize; sample[total_fx].start[ptr++] ^= 0x80);
  325.          if(load_stream == 1)
  326.          {
  327.              modsize = streamsize;
  328.              init_mod();
  329.          }
  330.          else {
  331.             sample[total_fx].end = streamsize;
  332.             sample[total_fx].loop = 0xFFFFFF;
  333.             sample[total_fx].volume = 0x40;
  334.             sample[total_fx].note = 60;
  335.             sample[total_fx].Priority = 0x80;
  336.             sample[total_fx].SeekFirst = 0x0F;
  337.             sample[total_fx].SeekLast = 0x0F;
  338.             sample[total_fx].FineTune = 0;
  339.             //{char fn[200];sprintf(fn,"s-%d.raw",total_fx); FILE*ff=fopen(fn,"wb");fwrite(sample[total_fx].start,1,streamsize,ff);fclose(ff);}
  340.             total_fx++;
  341.          }
  342.          used += streamsize;
  343.          load_stream = 0;
  344.          break;
  345.  
  346.       case 0x00: // reset flags - already done
  347.       case 0x08:
  348.       case 0xD1: // start stream
  349.          break;
  350.       default:
  351.          badgs[byte] = 1;
  352.          break;
  353.    }
  354. }
  355.  
  356. void GSHLE::start_fx(unsigned fx, unsigned ch, unsigned char vol, unsigned char note)
  357. {  
  358.    unsigned i; //Alone Coder 0.36.7
  359.    if (!fx) fx = cur_fx; // fx=0 - use default
  360.    if (vol == 0xFF) vol = sample[fx].volume;
  361.    if (note == 0xFF) note = sample[fx].note;
  362.    if(ch == 0xFF) // find free channel
  363.    {
  364.        unsigned SeekFirst = sample[fx].SeekFirst;
  365.        for(/*unsigned*/ i = 0; i < 4; i++)
  366.        {
  367.            if((SeekFirst & (1 << i)) && !chan[i].start)
  368.            {
  369.                ch = i;
  370.            }
  371.        }
  372.  
  373.        if(ch == 0xFF)
  374.        {
  375.            unsigned SeekLast = sample[fx].SeekLast;
  376.            for(i = 0; i < 4; i++)
  377.            {
  378.                if((SeekLast & (1 << i)) && !chan[i].start)
  379.                {
  380.                    ch = i;
  381.                }
  382.            }
  383.        }
  384.  
  385.        if(ch == 0xFF)
  386.        { // ╬сЁрсюЄър яЁшюЁшЄхЄют
  387.            unsigned SeekLast = sample[fx].SeekLast;
  388.            unsigned MinPrio = 0xFF;
  389.            unsigned MinPrioIdx = 0xFF;
  390.            for(i = 0; i < 4; i++)
  391.            {
  392.                if((SeekLast & (1 << i)) && (chan[i].Priority < MinPrio))
  393.                {
  394.                    MinPrio = chan[i].Priority;
  395.                    MinPrioIdx = i;
  396.                }
  397.            }
  398.  
  399.            if(MinPrioIdx == 0xFF)
  400.            {
  401.                return;
  402.            }
  403.  
  404.            if(sample[fx].Priority >= MinPrio)
  405.            {
  406.                ch = MinPrioIdx;
  407.            }
  408.        }
  409.    }
  410.  
  411.    if(ch == 0xFF) // ╧юфїюф ∙шщ ётюсюфэ√щ ърэры эх эрщфхэ
  412.    {
  413.        return;
  414.    }
  415.    chan[ch].volume = vol;
  416.    chan[ch].start = sample[fx].start;
  417.    chan[ch].loop = sample[fx].loop;
  418.    chan[ch].end = sample[fx].end;
  419.    chan[ch].Priority = sample[fx].Priority;
  420.    chan[ch].FineTune = sample[fx].FineTune;
  421.    chan[ch].ptr = 0;
  422.    chan[ch].freq = note2rate[note];
  423.    // ch0,1 - left, ch2,3 - right
  424.    startfx(&chan[ch], (ch & 2)? 1.0f : -1.0f);
  425. }
  426.  
  427. DWORD CALLBACK gs_render(HSTREAM handle, void *buffer, DWORD length, void *user);
  428.  
  429. DWORD CALLBACK gs_render(HSTREAM handle, void *buffer, DWORD length, void *user)
  430. {
  431.     (void)handle;
  432.  
  433.    GSHLE::CHANNEL *ch = (GSHLE::CHANNEL*)user;
  434.  
  435.    if (!ch->start)
  436.        return BASS_STREAMPROC_END;
  437.    if (ch->busy)
  438.    {
  439.        memset(buffer, 0, length);
  440.        return length;
  441.    }
  442.    for (unsigned i = 0; i < length; i++)
  443.    {
  444.       ((BYTE*)buffer)[i] = ch->start[ch->ptr++];
  445.       if (ch->ptr >= ch->end)
  446.       {
  447.          if (ch->end < ch->loop)
  448.          {
  449.              ch->start = nullptr;
  450.              return i + BASS_STREAMPROC_END;
  451.          }
  452.          else
  453.              ch->ptr = ch->loop;
  454.       }
  455.    }
  456.    return length;
  457. }
  458. #endif
  459.