void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) { #if 0 if (mode != M_INTELLIGENT) { mpu401_uart_init(mpu, addr); return; } #endif mpu->status = STATUS_INPUT_NOT_READY; mpu->irq = irq; mpu->queue_used = 0; mpu->queue_pos = 0; mpu->mode = M_UART; mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; pclog("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); mpu401_event_callback = 0; mpu401_eoi_callback = 0; mpu401_reset_callback = 0; io_sethandler(addr, 0x0002, mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); io_sethandler(0x2A20, 0x0010, NULL, NULL, NULL, imf_write, NULL, NULL, mpu); timer_add(MPU401_Event, &mpu401_event_callback, &mpu401_event_callback, mpu); timer_add(MPU401_EOIHandler, &mpu401_eoi_callback, &mpu401_eoi_callback, mpu); timer_add(MPU401_ResetDone, &mpu401_reset_callback, &mpu401_reset_callback, mpu); MPU401_Reset(mpu); }
/* HardMPU: Initialisation */ void MPU401_Init() { /* Initalise PIC code */ PIC_Init(); /* Initialise MIDI handler */ MIDI_Init(CONFIG_SYSEXDELAY,CONFIG_FAKEALLNOTESOFF); if (!MIDI_Available()) return; mpu.queue_used=0; mpu.queue_pos=0; mpu.mode=M_UART; mpu.intelligent=true; /* Default is on */ if (!mpu.intelligent) return; /* SOFTMPU: Moved IRQ 9 handler init to asm */ MPU401_Reset(); }
void MPU401_WriteCommand(Bit8u val) { /* SOFTMPU */ Bit8u i; /* SOFTMPU */ if (mpu.state.reset) { if (mpu.state.cmd_pending || (val!=0x3f && val!=0xff)) { mpu.state.cmd_pending=val+1; return; } PIC_RemoveEvents(RESET_DONE); mpu.state.reset=false; } if (val<=0x2f) { switch (val&3) { /* MIDI stop, start, continue */ case 1: {MIDI_RawOutByte(0xfc);break;} case 2: {MIDI_RawOutByte(0xfa);break;} case 3: {MIDI_RawOutByte(0xfb);break;} } /*if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",val);*/ /* SOFTMPU */ switch (val&0xc) { case 0x4: /* Stop */ PIC_RemoveEvents(MPU_EVENT); mpu.state.playing=false; for (i=0xb0;i<0xbf;i++) { /* All notes off */ MIDI_RawOutByte(i); MIDI_RawOutByte(0x7b); MIDI_RawOutByte(0); } break; case 0x8: /* Play */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started");*/ /* SOFTMPU */ mpu.state.playing=true; PIC_RemoveEvents(MPU_EVENT); PIC_AddEvent(MPU_EVENT,(Bitu)MPU401_TIMECONSTANT/(mpu.clock.tempo*mpu.clock.timebase)); ClrQueue(); break; } } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ if (mpu.state.cmask&(1<<(val&7))) QueueByte((Bit8u)mpu.playbuf[val&7].counter); } else if (val>=0xd0 && val<=0xd7) { /* Send data */ mpu.state.old_chan=mpu.state.channel; mpu.state.channel=val&7; mpu.state.wsd=true; mpu.state.wsm=false; mpu.state.wsd_start=true; } else switch (val) { case 0xdf: /* Send system message */ mpu.state.wsd=false; mpu.state.wsm=true; mpu.state.wsd_start=true; break; case 0x8e: /* Conductor */ mpu.state.cond_set=false; break; case 0x8f: mpu.state.cond_set=true; break; case 0x94: /* Clock to host */ mpu.clock.clock_to_host=false; break; case 0x95: mpu.clock.clock_to_host=true; break; case 0xc2: /* Internal timebase */ mpu.clock.timebase=48/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc3: mpu.clock.timebase=72/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc4: mpu.clock.timebase=96/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc5: mpu.clock.timebase=120/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc6: mpu.clock.timebase=144/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc7: mpu.clock.timebase=168/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc8: mpu.clock.timebase=192/(RTCFREQ/1000); /* SOFTMPU */ break; /* Commands with data byte */ case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: mpu.state.command_byte=val; break; /* Commands 0xa# returning data */ case 0xab: /* Request and clear recording counter */ QueueByte(MSG_MPU_ACK); QueueByte(0); return; case 0xac: /* Request version */ if (CONFIG_VERSIONFIX) { /* SOFTMPU: Fix missing music in Gateway by reversing version and ACK */ QueueByte(MPU401_VERSION); QueueByte(MSG_MPU_ACK); } else { QueueByte(MSG_MPU_ACK); QueueByte(MPU401_VERSION); } return; case 0xad: /* Request revision */ QueueByte(MSG_MPU_ACK); QueueByte(MPU401_REVISION); return; case 0xae: /* HardMPU: Request config */ QueueByte(MSG_MPU_ACK); QueueByte(mpu.config); return; case 0xaf: /* Request tempo */ QueueByte(MSG_MPU_ACK); QueueByte(mpu.clock.tempo); return; case 0xb1: /* Reset relative tempo */ mpu.clock.tempo_rel=40; break; case 0xb9: /* Clear play map */ case 0xb8: /* Clear play counters */ for (i=0xb0;i<0xbf;i++) { /* All notes off */ MIDI_RawOutByte((Bit8u)i); MIDI_RawOutByte(0x7b); MIDI_RawOutByte(0); } for (i=0;i<8;i++) { mpu.playbuf[i].counter=0; mpu.playbuf[i].type=T_OVERFLOW; } mpu.condbuf.counter=0; mpu.condbuf.type=T_OVERFLOW; if (!(mpu.state.conductor=mpu.state.cond_set)) mpu.state.cond_req=0; mpu.state.amask=mpu.state.tmask; mpu.state.req_mask=0; mpu.state.irq_pending=true; break; case 0xfe: /* HardMPU: Reset with config byte */ mpu.state.command_byte=val; break; case 0xff: /* Reset MPU-401 */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",val);*/ /* SOFTMPU */ PIC_AddEvent(RESET_DONE,MPU401_RESETBUSY); mpu.state.reset=true; MPU401_Reset(); if (mpu.mode==M_UART) return;//do not send ack in UART mode break; case 0x3f: /* UART mode */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Set UART mode %X",val);*/ /* SOFTMPU */ mpu.mode=M_UART; break; default: /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val);*/ break; } QueueByte(MSG_MPU_ACK); }
static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { uint8_t i; if (mpu->state.reset) { mpu->state.cmd_pending=val+1; return; } if (val<=0x2f) { switch (val&3) { /* MIDI stop, start, continue */ case 1: {midi_write(0xfc);break;} case 2: {midi_write(0xfa);break;} case 3: {midi_write(0xfb);break;} } // if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",(int)val); switch (val&0xc) { case 0x4: /* Stop */ mpu->state.playing=0; mpu401_event_callback = 0; for (i=0xb0;i<0xbf;i++) { /* All notes off */ midi_write(i); midi_write(0x7b); midi_write(0); } break; case 0x8: /* Play */ // LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started"); mpu->state.playing=1; mpu401_event_callback = (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000 * TIMER_USEC; ClrQueue(mpu); break; } } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ if (mpu->state.cmask&(1<<(val&7))) QueueByte(mpu, mpu->playbuf[val&7].counter); } else if (val>=0xd0 && val<=0xd7) { /* Send data */ mpu->state.old_chan=mpu->state.channel; mpu->state.channel=val&7; mpu->state.wsd=1; mpu->state.wsm=0; mpu->state.wsd_start=1; } else switch (val) { case 0xdf: /* Send system message */ mpu->state.wsd=0; mpu->state.wsm=1; mpu->state.wsd_start=1; break; case 0x8e: /* Conductor */ mpu->state.cond_set=0; break; case 0x8f: mpu->state.cond_set=1; break; case 0x94: /* Clock to host */ mpu->clock.clock_to_host=0; break; case 0x95: mpu->clock.clock_to_host=1; break; case 0xc2: /* Internal timebase */ mpu->clock.timebase=48; break; case 0xc3: mpu->clock.timebase=72; break; case 0xc4: mpu->clock.timebase=96; break; case 0xc5: mpu->clock.timebase=120; break; case 0xc6: mpu->clock.timebase=144; break; case 0xc7: mpu->clock.timebase=168; break; case 0xc8: mpu->clock.timebase=192; break; /* Commands with data byte */ case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: mpu->state.command_byte=val; break; /* Commands 0xa# returning data */ case 0xab: /* Request and clear recording counter */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, 0); return; case 0xac: /* Request version */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, MPU401_VERSION); return; case 0xad: /* Request revision */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, MPU401_REVISION); return; case 0xaf: /* Request tempo */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, mpu->clock.tempo); return; case 0xb1: /* Reset relative tempo */ mpu->clock.tempo_rel=40; break; case 0xb9: /* Clear play map */ case 0xb8: /* Clear play counters */ for (i=0xb0;i<0xbf;i++) { /* All notes off */ midi_write(i); midi_write(0x7b); midi_write(0); } for (i=0;i<8;i++) { mpu->playbuf[i].counter=0; mpu->playbuf[i].type=T_OVERFLOW; } mpu->condbuf.counter=0; mpu->condbuf.type=T_OVERFLOW; if (!(mpu->state.conductor=mpu->state.cond_set)) mpu->state.cond_req=0; mpu->state.amask=mpu->state.tmask; mpu->state.req_mask=0; mpu->state.irq_pending=1; break; case 0xff: /* Reset MPU-401 */ pclog("MPU-401:Reset %X\n",val); mpu401_reset_callback = MPU401_RESETBUSY * 33 * TIMER_USEC; mpu->state.reset=1; MPU401_Reset(mpu); #if 0 if (mpu->mode==M_UART) return;//do not send ack in UART mode #endif break; case 0x3f: /* UART mode */ pclog("MPU-401:Set UART mode %X\n",val); mpu->mode=M_UART; break; default:; //LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val); } QueueByte(mpu, MSG_MPU_ACK); }