Dave Phillips wrote:
Thanks for checking this out, Stas !If adding MIDI input capability in DOSemu is trivial, hopefully these reasons will convince you that it would still be greatly appreciated by some of us.
OK. Here goes the patch for midi input. Now at least I don't feel myself that guilty for not contributing for the half of a year already:)
About the patch: - Must be applied against the CVS version, as 1.1.99.1 lacks the IRQ support for MPU401 needed for vapimpu. - Don't forget to restart configure after applying. - Create a ~/.dosemu/dosemu-midi_in pipe and forward your midi data to it. - Let me know how it goes as I cant really test it (no midi keyboard, and I am not a musician at all).
--- src/include/config.h.in Thu Aug 28 00:58:37 2003
+++ src/include/config.h.in Fri Jan 9 02:16:16 2004
@@ -42,6 +42,7 @@
#define DEFAULT_CONFIG_SCRIPT "builtin" /* main configuration script */
#define DOSEMU_LOGLEVEL "dosemu.loglevel" /* logging configuration file */
#define DOSEMU_MIDI "dosemu-midi" /* fifo for midi daemon */
+#define DOSEMU_MIDI_IN "dosemu-midi_in" /* fifo for midi input */
EXTERN char *config_script_name INIT(DEFAULT_CONFIG_SCRIPT);
EXTERN char *config_script_path INIT(0);
@@ -63,6 +64,7 @@
EXTERN char *dexe_load_path INIT(dosemuhdimage_default);
EXTERN char *ipx_dos_ini_path INIT(ALTERNATE_ETC "/dos.ini");
EXTERN char *dosemu_midi_path INIT("~/" LOCALDIR_BASE_NAME "/run/" DOSEMU_MIDI);
+EXTERN char *dosemu_midi_in_path INIT("~/" LOCALDIR_BASE_NAME "/run/" DOSEMU_MIDI_IN);
#define DOSEMU_USERS_FILE dosemu_users_file_path
#define DOSEMU_LOGLEVEL_FILE dosemu_loglevel_file_path
@@ -76,6 +78,7 @@
#define IPX_DOS_INI_PATH ipx_dos_ini_path
#define DOSEMU_MAP_PATH dosemu_map_file_name
#define DOSEMU_MIDI_PATH dosemu_midi_path
+#define DOSEMU_MIDI_IN_PATH dosemu_midi_in_path
#endif /* not __ASM__ */
--- src/include/sound.h Sun Oct 26 19:35:57 2003
+++ src/include/sound.h Fri Jan 9 02:01:09 2004
@@ -227,6 +227,7 @@
#define QUEUE_SIZE 64
#define Q_HOLDS(q) (q.end - q.start)
+#define Q_AVAIL(q) (QUEUE_SIZE - q.end)
#define Q_CLEAR(q) (q.start = q.end = 0)
#define Q_PUT(q, v) { if (q.end < QUEUE_SIZE) q.output[q.end++] = v; }
#define Q_GET(q) ({ \
@@ -234,6 +235,12 @@
if (!Q_HOLDS(q)) Q_CLEAR(q); \
__ret; \
})
+#define Q_ADD(q, buf, len) ({ \
+ int __len = len; \
+ int __to_copy = MIN(__len, Q_AVAIL(q)); \
+ memcpy(q.output + q.end, buf, __to_copy); \
+ q.end += __to_copy; \
+})
typedef struct {
uint8_t output[QUEUE_SIZE]; /* Output Queue */
@@ -256,6 +263,8 @@
queue_t data;
/* Architecture specific procedures */
void (*data_write)(uint8_t data); /* process 1 MIDI byte */
+ int (*data_read)(uint8_t data[], int max_size);
+ void (*register_io_callback)(void (*io_callback)(void));
} mpu401_info;
/*
--- src/dosext/sound/sound.c Sun Oct 26 19:35:57 2003
+++ src/dosext/sound/sound.c Fri Jan 9 03:51:25 2004
@@ -347,7 +347,6 @@
/* DSP 8-bit IRQ Ack - SB */
S_printf("SB: 8-bit IRQ Ack: %x\n", SB_dsp.data);
sb_deactivate_irq(SB_IRQ_8BIT);
- SB_info.irq.active &= ~SB_IRQ_8BIT; /* may mean it never triggers! */
SB_dsp.ready = 0x7f;
if(SB_dsp.empty_state & DREQ_AT_EOI)
{
@@ -361,7 +360,6 @@
case 0x0F: /* 0x0F: DSP 16-bit IRQ - SB16 */
S_printf("SB: 16-bit IRQ Ack: %x\n", SB_dsp.data);
sb_deactivate_irq(SB_IRQ_16BIT);
- SB_info.irq.active &= ~SB_IRQ_16BIT; /* may mean it never triggers! */
SB_dsp.ready = 0x7f;
if(SB_dsp.empty_state & DREQ_AT_EOI)
{
@@ -648,7 +646,8 @@
case 0:
/* Read data port */
r=Q_GET(mpu401_info.data);
- S_printf("MPU401: Read data port = 0x%02x\n",r);
+ S_printf("MPU401: Read data port = 0x%02x, %i bytes still in queue\n",
+ r,Q_HOLDS(mpu401_info.data));
sb_deactivate_irq(SB_IRQ_MIDI);
break;
case 1:
@@ -661,6 +660,17 @@
return r;
}
+static void mpu401_io_callback(void)
+{
+ char buf[QUEUE_SIZE];
+ int n;
+ n = mpu401_info.data_read(buf, QUEUE_SIZE);
+ if (n <= 0)
+ return;
+ S_printf("MPU401: Processing IO callback, %i bytes\n", n);
+ Q_ADD(mpu401_info.data, buf, n);
+ sb_activate_irq(SB_IRQ_MIDI);
+}
/*
* Main IO Routines - Write
@@ -1824,6 +1834,7 @@
case 1:
/* Write command port */
S_printf("MPU401: Write 0x%02x to command port\n",value);
+ Q_CLEAR(mpu401_info.data);
Q_PUT(mpu401_info.data, 0xfe); /* A command is sent: MPU_ACK it next
time */
sb_activate_irq(SB_IRQ_MIDI);
switch (value) {
@@ -2596,7 +2607,7 @@
SB_info.version = SB_NONE;
}
- (void) FM_driver_init();
+ FM_driver_init();
}
static void mpu401_init(void)
@@ -2627,7 +2638,9 @@
Q_CLEAR(mpu401_info.data);
- (void) MPU_driver_init();
+ MPU_driver_init();
+
+ mpu401_info.register_io_callback(mpu401_io_callback);
}
@@ -2912,6 +2925,7 @@
S_printf("SB: Untriggering scheduled IRQ\n");
SB_dsp.empty_state &= ~IRQ_AT_EMPTY;
}
+ SB_info.irq.active &= ~type;
if(!(SB_info.irq.pending & type)) {
return;
}
--- src/base/init/parser.y.in Sun Dec 28 06:22:09 2003
+++ src/base/init/parser.y.in Fri Jan 9 02:14:42 2004
@@ -2215,6 +2215,7 @@
LOCALDIR = get_dosemu_local_home();
RUNDIR = mkdir_under(LOCALDIR, "run", 0);
DOSEMU_MIDI_PATH = assemble_path(RUNDIR, DOSEMU_MIDI, 0);
+ DOSEMU_MIDI_IN_PATH = assemble_path(RUNDIR, DOSEMU_MIDI_IN, 0);
}
static void lax_user_checking(void)
--- src/arch/linux/dosext/sound/linux_sound.c Sat Oct 11 16:54:05 2003
+++ src/arch/linux/dosext/sound/linux_sound.c Fri Jan 9 02:27:26 2004
@@ -65,6 +65,7 @@
/* MPU static vars */
static int mpu_fd = -1; /* -1 = closed */
+static int mpu_in_fd = -1; /* -1 = closed */
static boolean mpu_disabled = FALSE; /* TRUE if MIDI output disabled */
static void linux_sb_dma_set_blocksize(int blocksize, int fragsize)
@@ -653,9 +654,6 @@
SB_driver.DMA_complete = linux_sb_dma_complete;
SB_driver.DMA_set_blocksize = linux_sb_dma_set_blocksize;
- /* MPU-401 Functions */
- mpu401_info.data_write = linux_mpu401_data_write;
-
/* Miscellaneous Functions */
SB_driver.set_speed = linux_sb_set_speed;
SB_driver.play_buffer = NULL;
@@ -701,6 +699,11 @@
return linux_sb_get_version();
}
+void linux_mpu401_register_callback(void (*io_callback)(void))
+{
+ if (mpu_in_fd == -1) return;
+ add_to_io_select(mpu_in_fd, 1, io_callback);
+}
void linux_mpu401_data_write(uint8_t data)
{
@@ -724,6 +727,17 @@
}
}
+int linux_mpu401_data_read(uint8_t data[], int max_len)
+{
+ int ret;
+ if (mpu_in_fd == -1) return 0;
+ if ((ret = read(mpu_in_fd,data,max_len)) == -1) {
+ S_printf("MPU401:[Linux] Failed to write to file 'midi'
(%s)\n",
+ strerror(errno));
+ }
+ return ret;
+}
+
int FM_driver_init(void)
{
@@ -735,6 +749,14 @@
int MPU_driver_init(void)
{
S_printf("MPU:[Linux] MPU Driver Initialisation Called\n");
+
+ /* MPU-401 Functions */
+ mpu401_info.data_write = linux_mpu401_data_write;
+ mpu401_info.data_read = linux_mpu401_data_read;
+ mpu401_info.register_io_callback = linux_mpu401_register_callback;
+
+ mpu_in_fd = RPT_SYSCALL(open(DOSEMU_MIDI_IN_PATH, O_RDONLY | O_NONBLOCK, 0777));
+
mpu_disabled = FALSE;
/* Output a MIDI byte to an external file */
/* Added NONBLOCK to prevent hanging - Karcher */
--- src/arch/linux/dosext/sound/linux_sound.h Mon Oct 6 22:16:11 2003
+++ src/arch/linux/dosext/sound/linux_sound.h Fri Jan 9 01:24:20 2004
@@ -46,6 +46,8 @@
void linux_sb_dma_complete(void);
+int linux_mpu401_data_read(uint8_t data[], int max_len);
void linux_mpu401_data_write(uint8_t data);
+void linux_mpu401_register_callback(void (*io_callback)(void));
int linux_sb_get_free_fragments(int *total, int *free, int *bytes);
