something works
authornotaz <notasas@gmail.com>
Sun, 2 Feb 2025 23:15:44 +0000 (01:15 +0200)
committernotaz <notasas@gmail.com>
Wed, 19 Feb 2025 20:04:16 +0000 (22:04 +0200)
also need to reduce libpicofe delay:
diff --git a/sndout_sdl.c b/sndout_sdl.c
index c0c57ab..ec99abe 100644
--- a/sndout_sdl.c
+++ b/sndout_sdl.c
@@ -14,7 +14,7 @@

 // ~1/3s at 44kHz
 // set this to power of 2
-#define BUF_LEN 32768
+#define BUF_LEN (4*1024) //32768
 #define BUF_MASK (BUF_LEN - 1)

 static short buf[BUF_LEN];

Makefile
pico/sound/sound.c
pico/sound/ym2612.c

index 5cd200b..3bed72f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -49,7 +49,7 @@ else
 ifeq "$(DEBUG)" "0"
        CFLAGS += -O3 -DNDEBUG
 else
-       CFLAGS += -O1
+       CFLAGS += -O0
 endif
 endif
        LD = $(CC)
@@ -75,7 +75,7 @@ CFLAGS += $(call chkCCflag, -fno-tree-loop-if-convert -fipa-pta -fno-ipa-cp)
 endif
 else
 ifneq ($(STATIC_LINKING), 1)
-CFLAGS += $(call chkCCflag, -flto)
+#CFLAGS += $(call chkCCflag, -flto)
 endif
 endif
 
@@ -120,7 +120,7 @@ PicoDrive.zip: $(TARGET)
        cp platform/game_def.cfg .od_data
        $(STRIP) $< -o .od_data/picodrive
        cd .od_data && zip -9 -r ../$@ *
-all: PicoDrive.zip
+all: $(TARGET) # PicoDrive.zip
 endif
 
 ifeq "$(PLATFORM)" "win32"
index d7de6e9..34bcdf1 100644 (file)
@@ -68,11 +68,22 @@ PICO_INTERNAL void YM2413UnpackState(void)
   opll->adr = opll_buf.adr;\r
 }\r
 \r
+#include "mkbd.h"\r
+static int mkbd_fd = -1;\r
+\r
+static int midi_init(void);\r
+\r
 PICO_INTERNAL void PsndInit(void)\r
 {\r
   opll = OPLL_new(OSC_NTSC/15, OSC_NTSC/15/72);\r
   OPLL_setChipType(opll,0);\r
   OPLL_reset(opll);\r
+\r
+  if (mkbd_fd == -1)\r
+    mkbd_fd = midi_init();\r
+  if (mkbd_fd == -1)\r
+    exit(1);\r
+  printf("mkbd_fd: %d\n", mkbd_fd);\r
 }\r
 \r
 PICO_INTERNAL void PsndExit(void)\r
@@ -491,6 +502,125 @@ PICO_INTERNAL void PsndClear(void)
     memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len);\r
 }\r
 \r
+#include <stdint.h>\r
+#include <fcntl.h>\r
+#include <poll.h>\r
+#include <unistd.h>\r
+#include <errno.h>\r
+#include <alsa/asoundef.h>\r
+#define ESC_RED     "\033[1;31m"\r
+#define ESC_NORM    "\033[0m"\r
+\r
+static void cfail(const char *name, const char *arg)\r
+{\r
+  fprintf(stderr, "%s(%s): ", name, arg ? arg : "");\r
+  perror(NULL);\r
+  exit(1);\r
+}\r
+\r
+static int midi_init(void)\r
+{\r
+  char buf[16];\r
+  int i, fd;\r
+\r
+  for (i = 0; i < 10; i++) {\r
+    // /dev/snd/midiC%dD0 ?\r
+    snprintf(buf, sizeof(buf), "/dev/midi%d", i);\r
+    fd = open(buf, O_RDONLY);\r
+    if (fd != -1)\r
+      break;\r
+    if (errno != ENOENT)\r
+      perror(buf);\r
+  }\r
+  if (fd == -1) {\r
+    fprintf(stderr, ESC_RED "no midi" ESC_NORM "\n");\r
+    cfail("open", NULL);\r
+  }\r
+  return fd;\r
+}\r
+\r
+static void do_note(uint8_t note, int is_down)\r
+{\r
+  static uint32_t state[96/8/4];\r
+  int i, v = 0, release_all = 0;\r
+  if (note >= 96)\r
+    return;\r
+  if (is_down) {\r
+    state[note / 8 / 4] |= 1u << (note % 32u);\r
+    ym2612_inject(4, 0, 0, 0);\r
+    ym2612_inject(4, note / 12, note % 12, 1);\r
+  }\r
+  else {\r
+    state[note / 8 / 4] &= ~(1u << (note % 32u));\r
+    for (i = 0; i < ARRAY_SIZE(state); i++)\r
+      v |= state[i];\r
+    release_all = !v;\r
+    if (release_all)\r
+      ym2612_inject(4, 0, 0, 0);\r
+  }\r
+}\r
+\r
+static void midi_read(void)\r
+{\r
+  struct pollfd pfds[1] = {{ mkbd_fd, POLLIN, 0 }};\r
+  uint8_t status = 0;\r
+  uint8_t byte;\r
+  struct\r
+  {\r
+    uint8_t note;\r
+    uint8_t velocity;\r
+  } note;\r
+  int ret;\r
+\r
+  for (;;)\r
+  {\r
+    ret = poll(pfds, ARRAY_SIZE(pfds), 0);\r
+    if (ret < 0)\r
+      cfail("poll", NULL);\r
+    if (ret == 0)\r
+      return;\r
+    if (pfds[0].revents & ~POLLIN)\r
+      cfail("poll revents", NULL);\r
+\r
+    errno = 0;\r
+    if (read(mkbd_fd, &status, sizeof(status)) != sizeof(status))\r
+      cfail("read", NULL);\r
+    //printf("%d %02x\n", Pico.m.frame_count, status);\r
+    if (!(status & 0x80)) // not cmd\r
+      continue;\r
+    //channel = status & 0x0f;\r
+    switch (status & 0xf0) {\r
+      case MIDI_CMD_NOTE_ON: // 0x90\r
+        if (read(mkbd_fd, &note, sizeof(note)) != sizeof(note))\r
+          cfail("read", "note");\r
+        if (!note.velocity)\r
+          goto do_off;\r
+        do_note(note.note, 1);\r
+        break;\r
+      case MIDI_CMD_NOTE_OFF: // 0x80\r
+        if (read(mkbd_fd, &note, sizeof(note)) != sizeof(note))\r
+          cfail("read", NULL);\r
+        do_off:\r
+        do_note(note.note, 0);\r
+        break;\r
+      case 0xf0:\r
+        switch (status) {\r
+          case MIDI_CMD_COMMON_SYSEX:\r
+            do {\r
+              if (read(mkbd_fd, &byte, sizeof(byte)) != sizeof(byte))\r
+                cfail("read", NULL);\r
+            } while (byte != MIDI_CMD_COMMON_SYSEX_END); // 0xf7\r
+            break;\r
+          default:\r
+            goto unhandled;\r
+        }\r
+        break;\r
+      default:\r
+      unhandled:\r
+        break;\r
+    } // switch\r
+  }\r
+}\r
 \r
 static int PsndRender(int offset, int length)\r
 {\r
@@ -504,6 +634,9 @@ static int PsndRender(int offset, int length)
   buf32 = PsndBuffer+(offset<<stereo);\r
 \r
   pprof_start(sound);\r
+  // mkbd\r
+  if (offset == 0)\r
+    midi_read();\r
 \r
   // Add in parts of the PSG output not yet done\r
   if (length-psglen > 0 && PicoIn.sndOut) {\r
index ee84da2..a924e82 100644 (file)
@@ -1618,9 +1618,110 @@ static void OPNSetPres(int pres)
        }\r
 }\r
 \r
+#undef NDEBUG\r
+#include <assert.h>\r
+#include "mkbd.h"\r
+\r
+static\r
+const char *keys[] = { "c",  "c#",  "d", "d#", "e",  "f",  "f#", "g",  "g#",  "a",   "a#",  "b" };\r
+//                      643.8 682.1 722.6 765.6 811.1 859.3 910.4 964.6 1021.9 1082.7 1147.1 1215.3\r
+static int fns[] =    { 644,  682,  723,  766,  813,  860,  910,  965,  1023,  1084,  1148,  1216 };\r
+\r
+int mkbd_stolen_channels = (1<<3) | (1<<4);\r
+int mkbd_blk_fn_overide[6+4];\r
+int mkbd_fn_adj[6+4];\r
+\r
+// (144 * fnote * 2^20 / φM) / 2^(B-1)\r
+// x *144*2097152/7670443 / 16\r
+static void handle_blk_fn(int c, UINT8 *blk, UINT32 *fn, int do_log)\r
+{\r
+       int min_abs = 1<<11;\r
+       int min_di = 0;\r
+       int min_i = 0;\r
+       char buf[16];\r
+       int i;\r
+\r
+       for (i = 0; i < ARRAY_SIZE(fns); i++) {\r
+               int di = *fn - fns[i];\r
+               if (abs(di) < min_abs) {\r
+                       min_abs = abs(di);\r
+                       min_i = i;\r
+                       min_di = di;\r
+               }\r
+       }\r
+       mkbd_fn_adj[c] = min_di;\r
+\r
+       if (do_log) {\r
+               i = snprintf(buf, sizeof(buf), "%s%d", keys[min_i], *blk);\r
+               if (min_di != 0)\r
+                       snprintf(buf + i, sizeof(buf) - i, "%+d", min_di);\r
+               printf("%-8s", buf);\r
+       }\r
+\r
+       if (!do_log && mkbd_blk_fn_overide[c]) {\r
+               *blk = mkbd_blk_fn_overide[c] >> 11;\r
+               *fn = (mkbd_blk_fn_overide[c] & 0x7ff) + min_di;\r
+       }\r
+}\r
+\r
+static int is_stolen(int c)\r
+{\r
+       return mkbd_stolen_channels & (1 << c);\r
+}\r
+\r
+static void do_log_note(int c)\r
+{\r
+#if 0\r
+       int i, chans = (1<<0);// | (1<<4);\r
+       if (chans & (1 << c)) {\r
+               printf("%-5d ", Pico.m.frame_count);\r
+               for (i = 0; i < 6; i++) {\r
+                       UINT8 blk = ym2612.CH[i].block_fnum >> 11;\r
+                       UINT32 fn = ym2612.CH[i].block_fnum & 0x7ff;\r
+                       if (chans & (1 << i))\r
+                               handle_blk_fn(i, &blk, &fn, 1);\r
+               }\r
+               puts("");\r
+       }\r
+#endif\r
+}\r
+\r
+static void do_key_onoff(int c, int v)\r
+{\r
+       if(v&0x10) FM_KEYON(c,SLOT1); else FM_KEYOFF(c,SLOT1);\r
+       if(v&0x20) FM_KEYON(c,SLOT2); else FM_KEYOFF(c,SLOT2);\r
+       if(v&0x40) FM_KEYON(c,SLOT3); else FM_KEYOFF(c,SLOT3);\r
+       if(v&0x80) FM_KEYON(c,SLOT4); else FM_KEYOFF(c,SLOT4);\r
+}\r
+\r
+static int OPNWriteReg(int r, int v, int injecting);\r
+\r
+void ym2612_inject(int c, unsigned int octave, unsigned int key, int is_on)\r
+{\r
+       UINT8 fn_h_saved = ym2612.OPN.ST.fn_h;\r
+       UINT32 r = c < 3 ? c : (0x100 + (c - 3));\r
+       UINT32 val;\r
+\r
+       //printf("%s %d %d,%d %d\n", __func__, c, octave, key, is_on);\r
+       assert(octave < 8);\r
+       assert(key < ARRAY_SIZE(fns));\r
+       if (is_on) {\r
+               val = fns[key] + mkbd_fn_adj[c];\r
+               assert(val < (1u << 11));\r
+               val |= octave << 11;\r
+               mkbd_blk_fn_overide[c] = val;\r
+               ym2612.OPN.ST.fn_h = val >> 8;\r
+               OPNWriteReg(r | 0xa0, val & 0xff, 1);\r
+               ym2612.OPN.ST.fn_h = fn_h_saved;\r
+       }\r
+       else\r
+               mkbd_blk_fn_overide[c] = 0;\r
+\r
+       do_key_onoff(c, is_on ? 0xf0 : 0);\r
+}\r
 \r
 /* write a OPN register (0x30-0xff) */\r
-static int OPNWriteReg(int r, int v)\r
+static int OPNWriteReg(int r, int v, int injecting)\r
 {\r
        int ret = 1;\r
        FM_CH *CH;\r
@@ -1678,11 +1779,20 @@ static int OPNWriteReg(int r, int v)
                        {\r
                                UINT32 fn = ((UINT32)(ym2612.OPN.ST.fn_h & 7) << 8) | v;\r
                                UINT8 blk = ym2612.OPN.ST.fn_h >> 3;\r
+\r
+                               if (!injecting) {\r
+                                       handle_blk_fn(c, &blk, &fn, 0);\r
+                                       //if (is_stolen(c)) break;\r
+                               }\r
+\r
                                /* keyscale code */\r
                                CH->kcode = (blk<<2) | opn_fktable[fn >> 7];\r
                                /* phase increment counter */\r
                                CH->fc = fn_table[fn*2]>>(7-blk);\r
 \r
+                               if (!injecting && CH->block_fnum != ((blk<<11) | fn))\r
+                                       do_log_note(c);\r
+\r
                                /* store fnum in clear form for LFO PM calculations */\r
                                CH->block_fnum = (blk<<11) | fn;\r
 \r
@@ -1862,17 +1972,17 @@ void YM2612ResetChip_(void)
        reset_channels( &ym2612.CH[0] );\r
        for(i = 0xb6 ; i >= 0xb4 ; i-- )\r
        {\r
-               OPNWriteReg(i      ,0xc0);\r
-               OPNWriteReg(i|0x100,0xc0);\r
+               OPNWriteReg(i      ,0xc0,0);\r
+               OPNWriteReg(i|0x100,0xc0,0);\r
                ym2612.REGS[i      ] = 0xc0;\r
                ym2612.REGS[i|0x100] = 0xc0;\r
        }\r
        for(i = 0xb2 ; i >= 0x30 ; i-- )\r
        {\r
-               OPNWriteReg(i      ,0);\r
-               OPNWriteReg(i|0x100,0);\r
+               OPNWriteReg(i      ,0,0);\r
+               OPNWriteReg(i|0x100,0,0);\r
        }\r
-       for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(i,0);\r
+       for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(i,0,0);\r
        /* DAC mode clear */\r
        ym2612.dacen = 0;\r
        ym2612.dacout = 0;\r
@@ -1963,6 +2073,8 @@ int YM2612Write_(unsigned int a, unsigned int v)
                                        c = v & 0x03;\r
                                        if( c == 3 ) { ret=0; break; }\r
                                        if( v&0x04 ) c+=3;\r
+                                       if (is_stolen(c)) { ret = 0; break; }\r
+                                       //if (c == 4) printf("konoff %02x\n", v);\r
                                        if(v&0x10) FM_KEYON(c,SLOT1); else FM_KEYOFF(c,SLOT1);\r
                                        if(v&0x20) FM_KEYON(c,SLOT2); else FM_KEYOFF(c,SLOT2);\r
                                        if(v&0x40) FM_KEYON(c,SLOT3); else FM_KEYOFF(c,SLOT3);\r
@@ -1984,7 +2096,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
                        break;\r
                default:        /* 0x30-0xff OPN section */\r
                        /* write register */\r
-                       ret = OPNWriteReg(addr,v);\r
+                       ret = OPNWriteReg(addr,v,0);\r
                }\r
                break;\r
        }\r