Subversion Repositories Kolibri OS

Rev

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

  1. // DGen v1.29
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include "md.h"
  8. #include "rc-vars.h"
  9.  
  10. // REMEMBER NOT TO USE ANY STATIC variables, because they
  11. // will exist thoughout ALL megadrives!
  12. int md::myfm_write(int a, int v, int md)
  13. {
  14.         int sid = 0;
  15.         int pass = 1;
  16.  
  17.         (void)md;
  18.         a &= 3;
  19.         sid = ((a & 0x02) >> 1);
  20.         if ((a & 0x01) == 0) {
  21.                 fm_sel[sid] = v;
  22.                 goto end;
  23.         }
  24. #ifdef WITH_VGMDUMP
  25.         vgm_dump_ym2612(sid, fm_sel[sid], v);
  26. #endif
  27.         if (fm_sel[sid] == 0x2a) {
  28.                 dac_submit((uint8_t)v);
  29.                 pass = 0;
  30.         }
  31.         if (fm_sel[sid] == 0x2b) {
  32.                 dac_enable((uint8_t)v);
  33.                 pass = 0;
  34.         }
  35.         if (fm_sel[sid] == 0x27) {
  36.                 unsigned int now = frame_usecs();
  37.  
  38.                 if ((v & 0x01) && ((fm_reg[0][0x27] & 0x01) == 0)) {
  39.                         // load timer A
  40.                         fm_ticker[0] = 0;
  41.                         fm_ticker[1] = now;
  42.                 }
  43.                 if ((v & 0x02) && ((fm_reg[0][0x27] & 0x02) == 0)) {
  44.                         // load timer B
  45.                         fm_ticker[2] = 0;
  46.                         fm_ticker[3] = now;
  47.                 }
  48.                 // (v & 0x04) enable/disable timer A
  49.                 // (v & 0x08) enable/disable timer B
  50.                 if (v & 0x10) {
  51.                         // reset overflow A
  52.                         fm_tover &= ~0x01;
  53.                         v &= ~0x10;
  54.                         fm_reg[0][0x27] &= ~0x10;
  55.                 }
  56.                 if (v & 0x20) {
  57.                         // reset overflow B
  58.                         fm_tover &= ~0x02;
  59.                         v &= ~0x20;
  60.                         fm_reg[0][0x27] &= ~0x20;
  61.                 }
  62.         }
  63.         // stash all values
  64.         fm_reg[sid][(fm_sel[sid])] = v;
  65. end:
  66.         if (pass) {
  67.                 YM2612Write(0, a, v);
  68.                 if (dgen_mjazz) {
  69.                         YM2612Write(1, a, v);
  70.                         YM2612Write(2, a, v);
  71.                 }
  72.         }
  73.         return 0;
  74. }
  75.  
  76. int md::myfm_read(int a)
  77. {
  78.         fm_timer_callback();
  79.         return (fm_tover | (YM2612Read(0, (a & 3)) & ~0x03));
  80. }
  81.  
  82. int md::mysn_write(int d)
  83. {
  84. #ifdef WITH_VGMDUMP
  85.         vgm_dump_sn76496(d);
  86. #endif
  87.         SN76496Write(0, d);
  88.         return 0;
  89. }
  90.  
  91. int md::fm_timer_callback()
  92. {
  93.         // periods in microseconds for timers A and B
  94.         int amax = (18 * (1024 -
  95.                           (((fm_reg[0][0x24] << 2) |
  96.                             (fm_reg[0][0x25] & 0x03)) & 0x3ff)));
  97.         int bmax = (288 * (256 - (fm_reg[0][0x26] & 0xff)));
  98.         unsigned int now = frame_usecs();
  99.  
  100.         if ((fm_reg[0][0x27] & 0x01) && ((now - fm_ticker[1]) > 0)) {
  101.                 fm_ticker[0] += (now - fm_ticker[1]);
  102.                 fm_ticker[1] = now;
  103.                 if (fm_ticker[0] >= amax) {
  104.                         if (fm_reg[0][0x27] & 0x04)
  105.                                 fm_tover |= 0x01;
  106.                         fm_ticker[0] -= amax;
  107.                 }
  108.         }
  109.         if ((fm_reg[0][0x27] & 0x02) && ((now - fm_ticker[3]) > 0)) {
  110.                 fm_ticker[2] += (now - fm_ticker[3]);
  111.                 fm_ticker[3] = now;
  112.                 if (fm_ticker[2] >= bmax) {
  113.                         if (fm_reg[0][0x27] & 0x08)
  114.                                 fm_tover |= 0x02;
  115.                         fm_ticker[2] -= bmax;
  116.                 }
  117.         }
  118.         return 0;
  119. }
  120.  
  121. void md::fm_reset()
  122. {
  123.         memset(fm_sel, 0, sizeof(fm_sel));
  124.         fm_tover = 0x00;
  125.         memset(fm_ticker, 0, sizeof(fm_ticker));
  126.         memset(fm_reg, 0, sizeof(fm_reg));
  127.         YM2612ResetChip(0);
  128.         if (dgen_mjazz) {
  129.                 YM2612ResetChip(1);
  130.                 YM2612ResetChip(2);
  131.         }
  132.         SN76496_init(0,
  133.                      (((pal) ? PAL_MCLK : NTSC_MCLK) / 15),
  134.                      dgen_soundrate, 16);
  135. }
  136.  
  137. void md::dac_init()
  138. {
  139.         dac_enabled = true;
  140.         dac_len = 0;
  141. #ifndef NDEBUG
  142.         memset(dac_data, 0xff, sizeof(dac_data));
  143. #endif
  144. }
  145.  
  146. static const struct {
  147.         unsigned int samples;
  148.         unsigned int usecs;
  149. } per_frame[2] = {
  150.         { (44100 / 60), (1000000 / 60) },
  151.         { (44100 / 50), (1000000 / 50) },
  152. };
  153.  
  154. void md::dac_submit(uint8_t d)
  155. {
  156.         unsigned int usecs;
  157.         unsigned int index;
  158.         unsigned int i;
  159.  
  160.         if (!dac_enabled)
  161.                 return;
  162.         if (dac_len == elemof(dac_data))
  163.                 return;
  164.         usecs = frame_usecs();
  165.         index = ((usecs << 10) /
  166.                  ((per_frame[pal].usecs << 10) /
  167.                   elemof(dac_data)));
  168.         if (index >= elemof(dac_data))
  169.                 return;
  170.         dac_data[index] = d;
  171.         if (dac_len)
  172.                 d = dac_data[dac_len - 1];
  173.         for (i = dac_len; (i < index); ++i)
  174.                 dac_data[i] = d;
  175.         dac_len = (index + 1);
  176. }
  177.  
  178. void md::dac_enable(uint8_t d)
  179. {
  180.         dac_enabled = ((d & 0x80) >> 7);
  181. }
  182.  
  183. #ifdef WITH_VGMDUMP
  184.  
  185. void md::vgm_dump_ym2612(uint8_t a1, uint8_t reg, uint8_t data)
  186. {
  187.         if (vgm_dump) {
  188.                 uint8_t buf[] = { (uint8_t)(0x52 + a1), reg, data };
  189.  
  190.                 fwrite(buf, sizeof(buf), 1, vgm_dump_file);
  191.                 if ((a1 == 0) && (reg == 0x2a)) {
  192.                         unsigned int usecs = frame_usecs();
  193.                         unsigned int samples;
  194.                         unsigned int diff;
  195.  
  196.                         if (usecs > per_frame[pal].usecs)
  197.                                 usecs = per_frame[pal].usecs;
  198.                         samples = ((usecs *
  199.                                     ((per_frame[pal].samples << 20) /
  200.                                      per_frame[pal].usecs)) >> 20);
  201.                         diff = (samples - vgm_dump_dac_samples);
  202.                         if ((diff > 0) && (diff <= 16)) {
  203.                                 fputc((0x70 + (diff - 1)), vgm_dump_file);
  204.                                 vgm_dump_dac_wait += diff;
  205.                         }
  206.                         vgm_dump_dac_samples = samples;
  207.                 }
  208.         }
  209. }
  210.  
  211. void md::vgm_dump_sn76496(uint8_t data)
  212. {
  213.         if (vgm_dump) {
  214.                 uint8_t buf[] = { 0x50, data };
  215.  
  216.                 fwrite(buf, sizeof(buf), 1, vgm_dump_file);
  217.         }
  218. }
  219.  
  220. void md::vgm_dump_frame()
  221. {
  222.         unsigned int max = per_frame[pal].samples;
  223.  
  224.         if (!vgm_dump)
  225.                 return;
  226.         if (vgm_dump_dac_wait < max) {
  227.                 uint8_t buf[] = { 0x61, 0x00, 0x00 };
  228.                 uint16_t tmp = h2le16(max - vgm_dump_dac_wait);
  229.  
  230.                 memcpy(&buf[1], &tmp, sizeof(tmp));
  231.                 fwrite(buf, sizeof(buf), 1, vgm_dump_file);
  232.         }
  233.         vgm_dump_samples_total += max;
  234.         vgm_dump_dac_wait = 0;
  235.         vgm_dump_dac_samples = 0;
  236. }
  237.  
  238. // Generate VGM 1.70 header as defined by:
  239. // http://www.smspower.org/uploads/Music/vgmspec170.txt
  240. int md::vgm_dump_start(const char *name)
  241. {
  242.         uint8_t ym2612_buf[0x200];
  243.         uint8_t buf[0x100] = { 0 };
  244.         union {
  245.                 uint32_t u32;
  246.                 uint16_t u16;
  247.         } tmp;
  248.         unsigned int i;
  249.         int err;
  250.  
  251.         if (vgm_dump == true)
  252.                 vgm_dump_stop();
  253.         vgm_dump_file = dgen_fopen("vgm", name, DGEN_WRITE);
  254.         if (vgm_dump_file == NULL)
  255.                 return -1;
  256.         // 0x00: file identifier.
  257.         memcpy(&buf[0x00], "Vgm ", 4);
  258.         // 0x04: EoF offset. Not known yet.
  259.         // 0x08: version number (1.70).
  260.         tmp.u32 = 0x0170;
  261.         memcpy(&buf[0x08], &tmp.u32, 4);
  262.         // 0x0c: SN76489 (PSG) clock.
  263.         tmp.u32 = h2le32(clk0);
  264.         memcpy(&buf[0x0c], &tmp.u32, 4);
  265.         // 0x18: total # samples. Not known yet.
  266.         // 0x24: rate.
  267.         tmp.u32 = h2le32(vhz);
  268.         memcpy(&buf[0x24], &tmp.u32, 4);
  269.         // 0x28: SN76489 (PSG) feedback.
  270.         tmp.u16 = h2le16(0x0009);
  271.         memcpy(&buf[0x28], &tmp.u16, 2);
  272.         // 0x2a: SN76489 shift register width.
  273.         buf[0x2a] = 16;
  274.         // 0x2b: SN76489 flags.
  275.         buf[0x2b] = 0x00;
  276.         // 0x2c: YM2612 clock.
  277.         tmp.u32 = h2le32(clk1);
  278.         memcpy(&buf[0x2c], &tmp.u32, 4);
  279.         // 0x34: VGM data offset.
  280.         tmp.u32 = h2le32(sizeof(buf) - 0x34);
  281.         memcpy(&buf[0x34], &tmp.u32, 4);
  282.         // Dump VGM header.
  283.         if (fwrite(buf, sizeof(buf), 1, vgm_dump_file) != 1)
  284.                 goto error;
  285.         // Dump YM2612 registers directly.
  286.         YM2612_dump(0, ym2612_buf);
  287.         // Timers.
  288.         {
  289.                 uint8_t buf[] = {
  290.                         0x52, 0x24, (uint8_t)fm_reg[0][0x24],
  291.                         0x52, 0x25, (uint8_t)fm_reg[0][0x25],
  292.                         0x52, 0x26, (uint8_t)fm_reg[0][0x26],
  293.                         0x52, 0x27, (uint8_t)fm_reg[0][0x27],
  294.                 };
  295.  
  296.                 if (fwrite(buf, sizeof(buf), 1, vgm_dump_file) != 1)
  297.                         goto error;
  298.         }
  299.         // DAC.
  300.         {
  301.                 uint8_t buf[] = { 0x52, 0x2b, (uint8_t)(dac_enabled << 7) };
  302.  
  303.                 if (fwrite(buf, sizeof(buf), 1, vgm_dump_file) != 1)
  304.                         goto error;
  305.         }
  306.         // FM CH1-CH3.
  307.         for (i = 0x30; (i != 0x9e); ++i) {
  308.                 uint8_t buf[] = {
  309.                         0x52, (uint8_t)i, ym2612_buf[i],
  310.                         0x53, (uint8_t)i, ym2612_buf[i | 0x100],
  311.                 };
  312.  
  313.                 if (fwrite(buf, sizeof(buf), 1, vgm_dump_file) != 1)
  314.                         goto error;
  315.         }
  316.         // FM CH4-CH6.
  317.         for (i = 0xb0; (i != 0xb6); ++i) {
  318.                 uint8_t buf[] = {
  319.                         0x52, (uint8_t)i, ym2612_buf[i],
  320.                         0x53, (uint8_t)i, ym2612_buf[i | 0x100],
  321.                 };
  322.  
  323.                 if (fwrite(buf, sizeof(buf), 1, vgm_dump_file) != 1)
  324.                         goto error;
  325.         }
  326.         vgm_dump_samples_total = 0;
  327.         vgm_dump_dac_wait = 0;
  328.         vgm_dump_dac_samples = 0;
  329.         vgm_dump = true;
  330.         return 0;
  331. error:
  332.         err = errno;
  333.         fclose(vgm_dump_file);
  334.         vgm_dump_file = NULL;
  335.         errno = err;
  336.         return -1;
  337. }
  338.  
  339. void md::vgm_dump_stop()
  340. {
  341.         long pos;
  342.         uint32_t tmp;
  343.  
  344.         if (!vgm_dump)
  345.                 return;
  346.         // Append end of sound data.
  347.         fputc(0x66, vgm_dump_file);
  348.         pos = ftell(vgm_dump_file);
  349.         // Fill EoF offset.
  350.         fseek(vgm_dump_file, 0x04, SEEK_SET);
  351.         tmp = h2le32(pos - 4);
  352.         fwrite(&tmp, sizeof(tmp), 1, vgm_dump_file);
  353.         // Fill total number of samples.
  354.         fseek(vgm_dump_file, 0x18, SEEK_SET);
  355.         tmp = h2le32(vgm_dump_samples_total);
  356.         fwrite(&tmp, sizeof(tmp), 1, vgm_dump_file);
  357.         fclose(vgm_dump_file);
  358.         vgm_dump_file = NULL;
  359.         vgm_dump_samples_total = 0;
  360.         vgm_dump_dac_wait = 0;
  361.         vgm_dump_dac_samples = 0;
  362.         vgm_dump = false;
  363. }
  364.  
  365. #endif // WITH_VGMDUMP
  366.