From 4ca5d9583c0b40ffacba61c1c9134aa7a6bbdafc Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 3 Feb 2025 01:15:44 +0200 Subject: [PATCH] something works 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 | 6 +- pico/sound/sound.c | 133 ++++++++++++++++++++++++++++++++++++++++++++ pico/sound/ym2612.c | 126 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 255 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 5cd200ba..3bed72f1 100644 --- 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" diff --git a/pico/sound/sound.c b/pico/sound/sound.c index d7de6e9d..34bcdf11 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -68,11 +68,22 @@ PICO_INTERNAL void YM2413UnpackState(void) opll->adr = opll_buf.adr; } +#include "mkbd.h" +static int mkbd_fd = -1; + +static int midi_init(void); + PICO_INTERNAL void PsndInit(void) { opll = OPLL_new(OSC_NTSC/15, OSC_NTSC/15/72); OPLL_setChipType(opll,0); OPLL_reset(opll); + + if (mkbd_fd == -1) + mkbd_fd = midi_init(); + if (mkbd_fd == -1) + exit(1); + printf("mkbd_fd: %d\n", mkbd_fd); } PICO_INTERNAL void PsndExit(void) @@ -491,6 +502,125 @@ PICO_INTERNAL void PsndClear(void) memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len); } +#include +#include +#include +#include +#include +#include +#define ESC_RED "\033[1;31m" +#define ESC_NORM "\033[0m" + +static void cfail(const char *name, const char *arg) +{ + fprintf(stderr, "%s(%s): ", name, arg ? arg : ""); + perror(NULL); + exit(1); +} + +static int midi_init(void) +{ + char buf[16]; + int i, fd; + + for (i = 0; i < 10; i++) { + // /dev/snd/midiC%dD0 ? + snprintf(buf, sizeof(buf), "/dev/midi%d", i); + fd = open(buf, O_RDONLY); + if (fd != -1) + break; + if (errno != ENOENT) + perror(buf); + } + if (fd == -1) { + fprintf(stderr, ESC_RED "no midi" ESC_NORM "\n"); + cfail("open", NULL); + } + return fd; +} + +static void do_note(uint8_t note, int is_down) +{ + static uint32_t state[96/8/4]; + int i, v = 0, release_all = 0; + if (note >= 96) + return; + if (is_down) { + state[note / 8 / 4] |= 1u << (note % 32u); + ym2612_inject(4, 0, 0, 0); + ym2612_inject(4, note / 12, note % 12, 1); + } + else { + state[note / 8 / 4] &= ~(1u << (note % 32u)); + for (i = 0; i < ARRAY_SIZE(state); i++) + v |= state[i]; + release_all = !v; + if (release_all) + ym2612_inject(4, 0, 0, 0); + } +} + +static void midi_read(void) +{ + struct pollfd pfds[1] = {{ mkbd_fd, POLLIN, 0 }}; + uint8_t status = 0; + uint8_t byte; + struct + { + uint8_t note; + uint8_t velocity; + } note; + int ret; + + for (;;) + { + ret = poll(pfds, ARRAY_SIZE(pfds), 0); + if (ret < 0) + cfail("poll", NULL); + if (ret == 0) + return; + if (pfds[0].revents & ~POLLIN) + cfail("poll revents", NULL); + + errno = 0; + if (read(mkbd_fd, &status, sizeof(status)) != sizeof(status)) + cfail("read", NULL); + //printf("%d %02x\n", Pico.m.frame_count, status); + if (!(status & 0x80)) // not cmd + continue; + //channel = status & 0x0f; + switch (status & 0xf0) { + case MIDI_CMD_NOTE_ON: // 0x90 + if (read(mkbd_fd, ¬e, sizeof(note)) != sizeof(note)) + cfail("read", "note"); + if (!note.velocity) + goto do_off; + do_note(note.note, 1); + break; + case MIDI_CMD_NOTE_OFF: // 0x80 + if (read(mkbd_fd, ¬e, sizeof(note)) != sizeof(note)) + cfail("read", NULL); + do_off: + do_note(note.note, 0); + break; + case 0xf0: + switch (status) { + case MIDI_CMD_COMMON_SYSEX: + do { + if (read(mkbd_fd, &byte, sizeof(byte)) != sizeof(byte)) + cfail("read", NULL); + } while (byte != MIDI_CMD_COMMON_SYSEX_END); // 0xf7 + break; + default: + goto unhandled; + } + break; + default: + unhandled: + break; + } // switch + } +} static int PsndRender(int offset, int length) { @@ -504,6 +634,9 @@ static int PsndRender(int offset, int length) buf32 = PsndBuffer+(offset< 0 && PicoIn.sndOut) { diff --git a/pico/sound/ym2612.c b/pico/sound/ym2612.c index ee84da23..a924e82f 100644 --- a/pico/sound/ym2612.c +++ b/pico/sound/ym2612.c @@ -1618,9 +1618,110 @@ static void OPNSetPres(int pres) } } +#undef NDEBUG +#include +#include "mkbd.h" + +static +const char *keys[] = { "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b" }; +// 643.8 682.1 722.6 765.6 811.1 859.3 910.4 964.6 1021.9 1082.7 1147.1 1215.3 +static int fns[] = { 644, 682, 723, 766, 813, 860, 910, 965, 1023, 1084, 1148, 1216 }; + +int mkbd_stolen_channels = (1<<3) | (1<<4); +int mkbd_blk_fn_overide[6+4]; +int mkbd_fn_adj[6+4]; + +// (144 * fnote * 2^20 / φM) / 2^(B-1) +// x *144*2097152/7670443 / 16 +static void handle_blk_fn(int c, UINT8 *blk, UINT32 *fn, int do_log) +{ + int min_abs = 1<<11; + int min_di = 0; + int min_i = 0; + char buf[16]; + int i; + + for (i = 0; i < ARRAY_SIZE(fns); i++) { + int di = *fn - fns[i]; + if (abs(di) < min_abs) { + min_abs = abs(di); + min_i = i; + min_di = di; + } + } + mkbd_fn_adj[c] = min_di; + + if (do_log) { + i = snprintf(buf, sizeof(buf), "%s%d", keys[min_i], *blk); + if (min_di != 0) + snprintf(buf + i, sizeof(buf) - i, "%+d", min_di); + printf("%-8s", buf); + } + + if (!do_log && mkbd_blk_fn_overide[c]) { + *blk = mkbd_blk_fn_overide[c] >> 11; + *fn = (mkbd_blk_fn_overide[c] & 0x7ff) + min_di; + } +} + +static int is_stolen(int c) +{ + return mkbd_stolen_channels & (1 << c); +} + +static void do_log_note(int c) +{ +#if 0 + int i, chans = (1<<0);// | (1<<4); + if (chans & (1 << c)) { + printf("%-5d ", Pico.m.frame_count); + for (i = 0; i < 6; i++) { + UINT8 blk = ym2612.CH[i].block_fnum >> 11; + UINT32 fn = ym2612.CH[i].block_fnum & 0x7ff; + if (chans & (1 << i)) + handle_blk_fn(i, &blk, &fn, 1); + } + puts(""); + } +#endif +} + +static void do_key_onoff(int c, int v) +{ + if(v&0x10) FM_KEYON(c,SLOT1); else FM_KEYOFF(c,SLOT1); + if(v&0x20) FM_KEYON(c,SLOT2); else FM_KEYOFF(c,SLOT2); + if(v&0x40) FM_KEYON(c,SLOT3); else FM_KEYOFF(c,SLOT3); + if(v&0x80) FM_KEYON(c,SLOT4); else FM_KEYOFF(c,SLOT4); +} + +static int OPNWriteReg(int r, int v, int injecting); + +void ym2612_inject(int c, unsigned int octave, unsigned int key, int is_on) +{ + UINT8 fn_h_saved = ym2612.OPN.ST.fn_h; + UINT32 r = c < 3 ? c : (0x100 + (c - 3)); + UINT32 val; + + //printf("%s %d %d,%d %d\n", __func__, c, octave, key, is_on); + assert(octave < 8); + assert(key < ARRAY_SIZE(fns)); + if (is_on) { + val = fns[key] + mkbd_fn_adj[c]; + assert(val < (1u << 11)); + val |= octave << 11; + mkbd_blk_fn_overide[c] = val; + ym2612.OPN.ST.fn_h = val >> 8; + OPNWriteReg(r | 0xa0, val & 0xff, 1); + ym2612.OPN.ST.fn_h = fn_h_saved; + } + else + mkbd_blk_fn_overide[c] = 0; + + do_key_onoff(c, is_on ? 0xf0 : 0); +} /* write a OPN register (0x30-0xff) */ -static int OPNWriteReg(int r, int v) +static int OPNWriteReg(int r, int v, int injecting) { int ret = 1; FM_CH *CH; @@ -1678,11 +1779,20 @@ static int OPNWriteReg(int r, int v) { UINT32 fn = ((UINT32)(ym2612.OPN.ST.fn_h & 7) << 8) | v; UINT8 blk = ym2612.OPN.ST.fn_h >> 3; + + if (!injecting) { + handle_blk_fn(c, &blk, &fn, 0); + //if (is_stolen(c)) break; + } + /* keyscale code */ CH->kcode = (blk<<2) | opn_fktable[fn >> 7]; /* phase increment counter */ CH->fc = fn_table[fn*2]>>(7-blk); + if (!injecting && CH->block_fnum != ((blk<<11) | fn)) + do_log_note(c); + /* store fnum in clear form for LFO PM calculations */ CH->block_fnum = (blk<<11) | fn; @@ -1862,17 +1972,17 @@ void YM2612ResetChip_(void) reset_channels( &ym2612.CH[0] ); for(i = 0xb6 ; i >= 0xb4 ; i-- ) { - OPNWriteReg(i ,0xc0); - OPNWriteReg(i|0x100,0xc0); + OPNWriteReg(i ,0xc0,0); + OPNWriteReg(i|0x100,0xc0,0); ym2612.REGS[i ] = 0xc0; ym2612.REGS[i|0x100] = 0xc0; } for(i = 0xb2 ; i >= 0x30 ; i-- ) { - OPNWriteReg(i ,0); - OPNWriteReg(i|0x100,0); + OPNWriteReg(i ,0,0); + OPNWriteReg(i|0x100,0,0); } - for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(i,0); + for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(i,0,0); /* DAC mode clear */ ym2612.dacen = 0; ym2612.dacout = 0; @@ -1963,6 +2073,8 @@ int YM2612Write_(unsigned int a, unsigned int v) c = v & 0x03; if( c == 3 ) { ret=0; break; } if( v&0x04 ) c+=3; + if (is_stolen(c)) { ret = 0; break; } + //if (c == 4) printf("konoff %02x\n", v); if(v&0x10) FM_KEYON(c,SLOT1); else FM_KEYOFF(c,SLOT1); if(v&0x20) FM_KEYON(c,SLOT2); else FM_KEYOFF(c,SLOT2); if(v&0x40) FM_KEYON(c,SLOT3); else FM_KEYOFF(c,SLOT3); @@ -1984,7 +2096,7 @@ int YM2612Write_(unsigned int a, unsigned int v) break; default: /* 0x30-0xff OPN section */ /* write register */ - ret = OPNWriteReg(addr,v); + ret = OPNWriteReg(addr,v,0); } break; } -- 2.39.5