static void MPU401_Reset(void) { Bit8u i; /* SOFTMPU */ mpu.mode=(mpu.intelligent ? M_INTELLIGENT : M_UART); PIC_RemoveEvents(EOI_HANDLER); mpu.state.eoi_scheduled=false; mpu.state.wsd=false; mpu.state.wsm=false; mpu.state.conductor=false; mpu.state.cond_req=false; mpu.state.cond_set=false; mpu.state.playing=false; mpu.state.run_irq=false; mpu.state.irq_pending=false; mpu.state.cmask=0xff; mpu.state.amask=mpu.state.tmask=0; mpu.state.midi_mask=0xffff; mpu.state.data_onoff=0; mpu.state.command_byte=0; mpu.state.block_ack=false; mpu.clock.tempo=mpu.clock.old_tempo=100; mpu.clock.timebase=mpu.clock.old_timebase=120/(RTCFREQ/1000); mpu.clock.tempo_rel=mpu.clock.old_tempo_rel=40; mpu.clock.tempo_grad=0; mpu.clock.clock_to_host=false; mpu.clock.cth_rate=60; mpu.clock.cth_counter=0; ClrQueue(); mpu.state.req_mask=0; mpu.condbuf.counter=0; mpu.condbuf.type=T_OVERFLOW; for (i=0;i<8;i++) {mpu.playbuf[i].type=T_OVERFLOW;mpu.playbuf[i].counter=0;} }
static void MPU401_Reset(mpu_t *mpu) { uint8_t i; picintc(1 << mpu->irq); mpu->mode=(mpu->intelligent ? M_INTELLIGENT : M_UART); mpu->state.eoi_scheduled=0; mpu->state.wsd=0; mpu->state.wsm=0; mpu->state.conductor=0; mpu->state.cond_req=0; mpu->state.cond_set=0; mpu->state.playing=0; mpu->state.run_irq=0; mpu->state.irq_pending=0; mpu->state.cmask=0xff; mpu->state.amask=mpu->state.tmask=0; mpu->state.midi_mask=0xffff; mpu->state.data_onoff=0; mpu->state.command_byte=0; mpu->state.block_ack=0; mpu->clock.tempo=mpu->clock.old_tempo=100; mpu->clock.timebase=mpu->clock.old_timebase=120; mpu->clock.tempo_rel=mpu->clock.old_tempo_rel=40; mpu->clock.tempo_grad=0; mpu->clock.clock_to_host=0; mpu->clock.cth_rate=60; mpu->clock.cth_counter=0; ClrQueue(mpu); mpu->state.req_mask=0; mpu->condbuf.counter=0; mpu->condbuf.type=T_OVERFLOW; for (i=0;i<8;i++) {mpu->playbuf[i].type=T_OVERFLOW;mpu->playbuf[i].counter=0;} }
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); }