DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/hardware/mpu401.cpp
00001 /*
00002  *  Copyright (C) 2002-2012  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <string.h>
00021 #include "dosbox.h"
00022 #include "inout.h"
00023 #include "pic.h"
00024 #include "setup.h"
00025 #include "cpu.h"
00026 #include "support.h"
00027 #include "control.h"
00028 #include "setup.h"
00029 
00030 void MIDI_RawOutByte(Bit8u data);
00031 bool MIDI_Available(void);
00032 
00033 static void MPU401_Event(Bitu);
00034 static void MPU401_Reset(void);
00035 static void MPU401_ResetDone(Bitu);
00036 static void MPU401_EOIHandler(Bitu val=0);
00037 static void MPU401_EOIHandlerDispatch(void);
00038 
00039 #define MPU401_VERSION  0x15
00040 #define MPU401_REVISION 0x01
00041 #define MPU401_QUEUE 32
00042 #define MPU401_TIMECONSTANT (60000000/1000.0f)
00043 #define MPU401_RESETBUSY 27.0f
00044 
00045 enum MpuMode { M_UART,M_INTELLIGENT };
00046 enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND};
00047 
00048 static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen);
00049 
00050 /* Messages sent to MPU-401 from host */
00051 #define MSG_EOX                         0xf7
00052 #define MSG_OVERFLOW                    0xf8
00053 #define MSG_MARK                        0xfc
00054 
00055 /* Messages sent to host from MPU-401 */
00056 #define MSG_MPU_OVERFLOW                0xf8
00057 #define MSG_MPU_COMMAND_REQ             0xf9
00058 #define MSG_MPU_END                     0xfc
00059 #define MSG_MPU_CLOCK                   0xfd
00060 #define MSG_MPU_ACK                     0xfe
00061 
00062 static struct {
00063         bool intelligent;
00064         MpuMode mode;
00065         Bitu irq;
00066         Bit8u queue[MPU401_QUEUE];
00067         Bitu queue_pos,queue_used;
00068         struct track {
00069                 Bits counter;
00070                 Bit8u value[8],sys_val;
00071                 Bit8u vlength,length;
00072                 MpuDataType type;
00073         } playbuf[8],condbuf;
00074         struct {
00075                 bool conductor,cond_req,cond_set, block_ack;
00076                 bool playing,reset;
00077                 bool wsd,wsm,wsd_start;
00078                 bool run_irq,irq_pending;
00079                 bool send_now;
00080                 bool eoi_scheduled;
00081                 Bits data_onoff;
00082                 Bitu command_byte,cmd_pending;
00083                 Bit8u tmask,cmask,amask;
00084                 Bit16u midi_mask;
00085                 Bit16u req_mask;
00086                 Bit8u channel,old_chan;
00087         } state;
00088         struct {
00089                 Bit8u timebase,old_timebase;
00090                 Bit8u tempo,old_tempo;
00091                 Bit8u tempo_rel,old_tempo_rel;
00092                 Bit8u tempo_grad;
00093                 Bit8u cth_rate,cth_counter;
00094                 bool clock_to_host,cth_active;
00095         } clock;
00096 } mpu;
00097 
00098 int MPU401_GetIRQ() {
00099         return (int)mpu.irq;
00100 }
00101 
00102 static void QueueByte(Bit8u data) {
00103         if (mpu.state.block_ack) {mpu.state.block_ack=false;return;}
00104         if (mpu.queue_used==0 && mpu.intelligent) {
00105                 mpu.state.irq_pending=true;
00106                 PIC_ActivateIRQ(mpu.irq);
00107         }
00108         if (mpu.queue_used<MPU401_QUEUE) {
00109                 Bitu pos=mpu.queue_used+mpu.queue_pos;
00110                 if (mpu.queue_pos>=MPU401_QUEUE) mpu.queue_pos-=MPU401_QUEUE;
00111                 if (pos>=MPU401_QUEUE) pos-=MPU401_QUEUE;
00112                 mpu.queue_used++;
00113                 mpu.queue[pos]=data;
00114         } else LOG(LOG_MISC,LOG_NORMAL)("MPU401:Data queue full");
00115 }
00116 
00117 static void ClrQueue(void) {
00118         mpu.queue_used=0;
00119         mpu.queue_pos=0;
00120 }
00121 
00122 static Bitu MPU401_ReadStatus(Bitu port,Bitu iolen) {
00123     (void)iolen;//UNUSED
00124     (void)port;//UNUSED
00125         Bit8u ret=0x3f; /* Bits 6 and 7 clear */
00126         if (mpu.state.cmd_pending) ret|=0x40;
00127         if (!mpu.queue_used) ret|=0x80;
00128         return ret;
00129 }
00130 
00131 static void MPU401_WriteCommand(Bitu port,Bitu val,Bitu iolen) {
00132     (void)iolen;//UNUSED
00133     (void)port;//UNUSED
00134         if (mpu.state.reset) {mpu.state.cmd_pending=val+1;return;}
00135         if (val<=0x2f) {
00136                 switch (val&3) { /* MIDI stop, start, continue */
00137                         case 1: {MIDI_RawOutByte(0xfc);break;}
00138                         case 2: {MIDI_RawOutByte(0xfa);break;}
00139                         case 3: {MIDI_RawOutByte(0xfb);break;}
00140                 }
00141                 if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",(int)val);
00142                 switch (val&0xc) {
00143                         case  0x4:      /* Stop */
00144                                 PIC_RemoveEvents(MPU401_Event);
00145                                 mpu.state.playing=false;
00146                                 for (Bitu i=0xb0;i<0xbf;i++) {  /* All notes off */
00147                                         MIDI_RawOutByte(i);
00148                                         MIDI_RawOutByte(0x7b);
00149                                         MIDI_RawOutByte(0);
00150                                 }
00151                                 break;
00152                         case 0x8:       /* Play */
00153                                 LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started");
00154                                 mpu.state.playing=true;
00155                                 PIC_RemoveEvents(MPU401_Event);
00156                                 PIC_AddEvent(MPU401_Event,MPU401_TIMECONSTANT/(mpu.clock.tempo*mpu.clock.timebase));
00157                                 ClrQueue();
00158                                 break;
00159                 }
00160         }
00161         else if (val>=0xa0 && val<=0xa7) {      /* Request play counter */
00162                 if (mpu.state.cmask&(1<<(val&7))) QueueByte(mpu.playbuf[val&7].counter);
00163         }
00164         else if (val>=0xd0 && val<=0xd7) {      /* Send data */
00165                 mpu.state.old_chan=mpu.state.channel;
00166                 mpu.state.channel=val&7;
00167                 mpu.state.wsd=true;
00168                 mpu.state.wsm=false;
00169                 mpu.state.wsd_start=true;
00170         }
00171         else
00172         switch (val) {
00173                 case 0xdf:      /* Send system message */
00174                         mpu.state.wsd=false;
00175                         mpu.state.wsm=true;
00176                         mpu.state.wsd_start=true;
00177                         break;
00178                 case 0x8e:      /* Conductor */
00179                         mpu.state.cond_set=false;
00180                         break;
00181                 case 0x8f:
00182                         mpu.state.cond_set=true;
00183                         break;
00184                 case 0x94: /* Clock to host */
00185                         mpu.clock.clock_to_host=false;
00186                         break;
00187                 case 0x95:
00188                         mpu.clock.clock_to_host=true;
00189                         break;
00190                 case 0xc2: /* Internal timebase */
00191                         mpu.clock.timebase=48;
00192                         break;
00193                 case 0xc3:
00194                         mpu.clock.timebase=72;
00195                         break;
00196                 case 0xc4:
00197                         mpu.clock.timebase=96;
00198                         break;
00199                 case 0xc5:
00200                         mpu.clock.timebase=120;
00201                         break;
00202                 case 0xc6:
00203                         mpu.clock.timebase=144;
00204                         break;
00205                 case 0xc7:
00206                         mpu.clock.timebase=168;
00207                         break;
00208                 case 0xc8:
00209                         mpu.clock.timebase=192;
00210                         break;
00211                 /* Commands with data byte */
00212                 case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: 
00213                 case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef:
00214                         mpu.state.command_byte=val;
00215                         break;
00216                 /* Commands 0xa# returning data */
00217                 case 0xab:      /* Request and clear recording counter */
00218                         QueueByte(MSG_MPU_ACK);
00219                         QueueByte(0);
00220                         return;
00221                 case 0xac:      /* Request version */
00222                         QueueByte(MSG_MPU_ACK);
00223                         QueueByte(MPU401_VERSION);
00224                         return;
00225                 case 0xad:      /* Request revision */
00226                         QueueByte(MSG_MPU_ACK);
00227                         QueueByte(MPU401_REVISION);
00228                         return;
00229                 case 0xaf:      /* Request tempo */
00230                         QueueByte(MSG_MPU_ACK);
00231                         QueueByte(mpu.clock.tempo);
00232                         return;
00233                 case 0xb1:      /* Reset relative tempo */
00234             mpu.clock.old_tempo_rel=mpu.clock.tempo_rel;
00235             mpu.clock.tempo_rel=0x40;
00236                         break;
00237                 case 0xb9:      /* Clear play map */
00238                 case 0xb8:      /* Clear play counters */
00239                         for (Bitu i=0xb0;i<0xbf;i++) {  /* All notes off */
00240                                 MIDI_RawOutByte(i);
00241                                 MIDI_RawOutByte(0x7b);
00242                                 MIDI_RawOutByte(0);
00243                         }
00244                         for (Bitu i=0;i<8;i++) {
00245                                 mpu.playbuf[i].counter=0;
00246                                 mpu.playbuf[i].type=T_OVERFLOW;
00247                         }
00248                         mpu.condbuf.counter=0;
00249                         mpu.condbuf.type=T_OVERFLOW;
00250                         if (!(mpu.state.conductor=mpu.state.cond_set)) mpu.state.cond_req=0;
00251                         mpu.state.amask=mpu.state.tmask;
00252                         mpu.state.req_mask=0;
00253                         mpu.state.irq_pending=true;
00254                         break;
00255                 case 0xff:      /* Reset MPU-401 */
00256                         LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",(int)val);
00257                         PIC_AddEvent(MPU401_ResetDone,MPU401_RESETBUSY);
00258                         mpu.state.reset=true;
00259                         MPU401_Reset();
00260                         if (mpu.mode==M_UART) return;//do not send ack in UART mode
00261                         break;
00262                 case 0x3f:      /* UART mode */
00263                         LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Set UART mode %X",(int)val);
00264                         mpu.mode=M_UART;
00265                         break;
00266                 default:;
00267                         //LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val);
00268         }
00269         QueueByte(MSG_MPU_ACK);
00270 }
00271 
00272 static Bitu MPU401_ReadData(Bitu port,Bitu iolen) {
00273     (void)iolen;//UNUSED
00274     (void)port;//UNUSED
00275         Bit8u ret=MSG_MPU_ACK;
00276         if (mpu.queue_used) {
00277                 if (mpu.queue_pos>=MPU401_QUEUE) mpu.queue_pos-=MPU401_QUEUE;
00278                 ret=mpu.queue[mpu.queue_pos];
00279                 mpu.queue_pos++;mpu.queue_used--;
00280         }
00281         if (!mpu.intelligent) return ret;
00282 
00283         if (mpu.queue_used == 0) PIC_DeActivateIRQ(mpu.irq);
00284 
00285         if (ret>=0xf0 && ret<=0xf7) { /* MIDI data request */
00286                 mpu.state.channel=ret&7;
00287                 mpu.state.data_onoff=0;
00288                 mpu.state.cond_req=false;
00289         }
00290         if (ret==MSG_MPU_COMMAND_REQ) {
00291                 mpu.state.data_onoff=0;
00292                 mpu.state.cond_req=true;
00293                 if (mpu.condbuf.type!=T_OVERFLOW) {
00294                         mpu.state.block_ack=true;
00295                         MPU401_WriteCommand(0x331,mpu.condbuf.value[0],1);
00296                         if (mpu.state.command_byte) MPU401_WriteData(0x330,mpu.condbuf.value[1],1);
00297                 }
00298         mpu.condbuf.type=T_OVERFLOW;
00299         }
00300         if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) {
00301                 mpu.state.data_onoff=-1;
00302                 MPU401_EOIHandlerDispatch();
00303         }
00304         return ret;
00305 }
00306 
00307 static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) {
00308     (void)iolen;//UNUSED
00309     (void)port;//UNUSED
00310         if (mpu.mode==M_UART) {MIDI_RawOutByte(val);return;}
00311         switch (mpu.state.command_byte) {       /* 0xe# command data */
00312                 case 0x00:
00313                         break;
00314                 case 0xe0:      /* Set tempo */
00315                         mpu.state.command_byte=0;
00316                         mpu.clock.tempo=val;
00317                         return;
00318                 case 0xe1:      /* Set relative tempo */
00319                         mpu.state.command_byte=0;
00320             mpu.clock.old_tempo_rel=mpu.clock.tempo_rel;
00321             mpu.clock.tempo_rel=val;
00322             if (val != 0x40) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Relative tempo change value 0x%x (%.3f)",(unsigned int)val,(double)val / 0x40);
00323                         return;
00324                 case 0xe7:      /* Set internal clock to host interval */
00325                         mpu.state.command_byte=0;
00326                         mpu.clock.cth_rate=val>>2;
00327                         return;
00328                 case 0xec:      /* Set active track mask */
00329                         mpu.state.command_byte=0;
00330                         mpu.state.tmask=val;
00331                         return;
00332                 case 0xed: /* Set play counter mask */
00333                         mpu.state.command_byte=0;
00334                         mpu.state.cmask=val;
00335                         return;
00336                 case 0xee: /* Set 1-8 MIDI channel mask */
00337                         mpu.state.command_byte=0;
00338                         mpu.state.midi_mask&=0xff00;
00339                         mpu.state.midi_mask|=val;
00340                         return;
00341                 case 0xef: /* Set 9-16 MIDI channel mask */
00342                         mpu.state.command_byte=0;
00343                         mpu.state.midi_mask&=0x00ff;
00344                         mpu.state.midi_mask|=((Bit16u)val)<<8;
00345                         return;
00346                 //case 0xe2:    /* Set graduation for relative tempo */
00347                 //case 0xe4:    /* Set metronome */
00348                 //case 0xe6:    /* Set metronome measure length */
00349                 default:
00350                         mpu.state.command_byte=0;
00351                         return;
00352         }
00353         static Bitu length,cnt,posd;
00354         if (mpu.state.wsd) {    /* Directly send MIDI message */
00355                 if (mpu.state.wsd_start) {
00356                         mpu.state.wsd_start=0;
00357                         cnt=0;
00358                                 switch (val&0xf0) {
00359                                         case 0xc0:case 0xd0:
00360                                                 mpu.playbuf[mpu.state.channel].value[0]=val;
00361                                                 length=2;
00362                                                 break;
00363                                         case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0:
00364                                                 mpu.playbuf[mpu.state.channel].value[0]=val;
00365                                                 length=3;
00366                                                 break;
00367                                         case 0xf0:
00368                                                 LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal WSD byte");
00369                                                 mpu.state.wsd=0;
00370                                                 mpu.state.channel=mpu.state.old_chan;
00371                                                 return;
00372                                         default: /* MIDI with running status */
00373                                                 cnt++;
00374                                                 MIDI_RawOutByte(mpu.playbuf[mpu.state.channel].value[0]);
00375                                 }
00376                 }
00377                 if (cnt<length) {MIDI_RawOutByte(val);cnt++;}
00378                 if (cnt==length) {
00379                         mpu.state.wsd=0;
00380                         mpu.state.channel=mpu.state.old_chan;
00381                 }
00382                 return;
00383         }
00384         if (mpu.state.wsm) {    /* Directly send system message */
00385                 if (val==MSG_EOX) {MIDI_RawOutByte(MSG_EOX);mpu.state.wsm=0;return;}
00386                 if (mpu.state.wsd_start) {
00387                         mpu.state.wsd_start=0;
00388                         cnt=0;
00389                         switch (val) {
00390                                 case 0xf2:{ length=3; break;}
00391                                 case 0xf3:{ length=2; break;}
00392                                 case 0xf6:{ length=1; break;}
00393                                 case 0xf0:{ length=0; break;}
00394                                 default:
00395                                         length=0;
00396                         }
00397                 }
00398                 if (!length || cnt<length) {MIDI_RawOutByte(val);cnt++;}
00399                 if (cnt==length) mpu.state.wsm=0;
00400                 return;
00401         }
00402         if (mpu.state.cond_req) { /* Command */
00403                 switch (mpu.state.data_onoff) {
00404                         case -1:
00405                                 return;
00406                         case  0: /* Timing byte */
00407                                 mpu.condbuf.vlength=0;
00408                                 if (val<0xf0) mpu.state.data_onoff++;
00409                                 else {
00410                                         mpu.state.data_onoff=-1;
00411                                         MPU401_EOIHandlerDispatch();
00412                                         return;
00413                                 }
00414                                 if (val==0) mpu.state.send_now=true;
00415                                 else mpu.state.send_now=false;
00416                                 mpu.condbuf.counter=(Bits)val;
00417                                 break;
00418                         case  1: /* Command byte #1 */
00419                                 mpu.condbuf.type=T_COMMAND;
00420                                 if (val==0xf8 || val==0xf9) mpu.condbuf.type=T_OVERFLOW;
00421                                 mpu.condbuf.value[mpu.condbuf.vlength]=val;
00422                                 mpu.condbuf.vlength++;
00423                                 if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch();
00424                                 else mpu.state.data_onoff++;
00425                                 break;
00426                         case  2:/* Command byte #2 */
00427                                 mpu.condbuf.value[mpu.condbuf.vlength]=val;
00428                                 mpu.condbuf.vlength++;
00429                                 MPU401_EOIHandlerDispatch();
00430                                 break;
00431                 }
00432                 return;
00433         }
00434         switch (mpu.state.data_onoff) { /* Data */
00435                 case   -1:
00436                         return;
00437                 case    0: /* Timing byte */
00438                         if (val<0xf0) mpu.state.data_onoff=1;
00439                         else {
00440                                 mpu.state.data_onoff=-1;
00441                                 MPU401_EOIHandlerDispatch();
00442                                 return;
00443                         }
00444                         if (val==0) mpu.state.send_now=true;
00445                         else mpu.state.send_now=false;
00446                         mpu.playbuf[mpu.state.channel].counter=(Bits)val;
00447                         break;
00448                 case    1: /* MIDI */
00449                         mpu.playbuf[mpu.state.channel].vlength++;
00450                         posd=mpu.playbuf[mpu.state.channel].vlength;
00451                         if (posd==1) {
00452                                 switch (val&0xf0) {
00453                                         case 0xf0: /* System message or mark */
00454                                                 if (val>0xf7) {
00455                                                         mpu.playbuf[mpu.state.channel].type=T_MARK;
00456                                                         mpu.playbuf[mpu.state.channel].sys_val=val;
00457                                                         length=1;
00458                                                 } else {
00459                                                         LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message");
00460                                                         mpu.playbuf[mpu.state.channel].type=T_MIDI_SYS;
00461                                                         mpu.playbuf[mpu.state.channel].sys_val=val;
00462                                                         length=1;
00463                                                 }
00464                                                 break;
00465                                         case 0xc0: case 0xd0: /* MIDI Message */
00466                                                 mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM;
00467                                                 length=mpu.playbuf[mpu.state.channel].length=2;
00468                                                 break;
00469                                         case 0x80: case 0x90: case 0xa0:  case 0xb0: case 0xe0: 
00470                                                 mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM;
00471                                                 length=mpu.playbuf[mpu.state.channel].length=3;
00472                                                 break;
00473                                         default: /* MIDI data with running status */
00474                                                 posd++;
00475                                                 mpu.playbuf[mpu.state.channel].vlength++;
00476                                                 mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM;
00477                                                 length=mpu.playbuf[mpu.state.channel].length;
00478                                                 break;
00479                                 }
00480                         }
00481                         if (!(posd==1 && val>=0xf0)) mpu.playbuf[mpu.state.channel].value[posd-1]=val;
00482                         if (posd==length) MPU401_EOIHandlerDispatch();
00483         }
00484 }
00485 
00486 static void MPU401_IntelligentOut(Bit8u chan) {
00487         Bitu val;
00488         switch (mpu.playbuf[chan].type) {
00489                 case T_OVERFLOW:
00490                         break;
00491                 case T_MARK:
00492                         val=mpu.playbuf[chan].sys_val;
00493                         if (val==0xfc) {
00494                                 MIDI_RawOutByte(val);
00495                                 mpu.state.amask&=~(1<<chan);
00496                                 mpu.state.req_mask&=~(1<<chan);
00497                         }
00498                         break;
00499                 case T_MIDI_NORM:
00500                         for (Bitu i=0;i<mpu.playbuf[chan].vlength;i++)
00501                                 MIDI_RawOutByte(mpu.playbuf[chan].value[i]);
00502                         break;
00503                 default:
00504                         break;
00505         }
00506 }
00507 
00508 static void UpdateTrack(Bit8u chan) {
00509         MPU401_IntelligentOut(chan);
00510         if (mpu.state.amask&(1<<chan)) {
00511                 mpu.playbuf[chan].vlength=0;
00512                 mpu.playbuf[chan].type=T_OVERFLOW;
00513                 mpu.playbuf[chan].counter=0xf0;
00514                 mpu.state.req_mask|=(1<<chan);
00515         } else {
00516                 if (mpu.state.amask==0 && !mpu.state.conductor) mpu.state.req_mask|=(1<<12);
00517         }
00518 }
00519 
00520 static void UpdateConductor(void) {
00521     for (unsigned int i=0;i < mpu.condbuf.vlength;i++) {
00522         if (mpu.condbuf.value[i] == 0xfc) {
00523             mpu.condbuf.value[i] = 0;
00524             mpu.state.conductor=false;
00525             mpu.state.req_mask&=~(1<<9);
00526             if (mpu.state.amask==0) mpu.state.req_mask|=(1<<12);
00527             return;
00528         }
00529     }
00530 
00531         mpu.condbuf.vlength=0;
00532         mpu.condbuf.counter=0xf0;
00533         mpu.state.req_mask|=(1<<9);
00534 }
00535 
00536 static void MPU401_Event(Bitu val) {
00537     (void)val;//UNUSED
00538         if (mpu.mode==M_UART) return;
00539         if (mpu.state.irq_pending) goto next_event;
00540         for (Bitu i=0;i<8;i++) { /* Decrease counters */
00541                 if (mpu.state.amask&(1<<i)) {
00542                         mpu.playbuf[i].counter--;
00543                         if (mpu.playbuf[i].counter<=0) UpdateTrack(i);
00544                 }
00545         }               
00546         if (mpu.state.conductor) {
00547                 mpu.condbuf.counter--;
00548                 if (mpu.condbuf.counter<=0) UpdateConductor();
00549         }
00550         if (mpu.clock.clock_to_host) {
00551                 mpu.clock.cth_counter++;
00552                 if (mpu.clock.cth_counter >= mpu.clock.cth_rate) {
00553                         mpu.clock.cth_counter=0;
00554                         mpu.state.req_mask|=(1<<13);
00555                 }
00556         }
00557         if (!mpu.state.irq_pending && mpu.state.req_mask) MPU401_EOIHandler();
00558 next_event:
00559         PIC_RemoveEvents(MPU401_Event);
00560         Bitu new_time;
00561         if ((new_time=(Bitu)((mpu.clock.tempo*mpu.clock.timebase*mpu.clock.tempo_rel)/0x40))==0) return;
00562         PIC_AddEvent(MPU401_Event,MPU401_TIMECONSTANT/new_time);
00563 }
00564 
00565 
00566 static void MPU401_EOIHandlerDispatch(void) {
00567         if (mpu.state.send_now) {
00568                 mpu.state.eoi_scheduled=true;
00569                 PIC_AddEvent(MPU401_EOIHandler,0.06f); //Possible a bit longer
00570         }
00571         else if (!mpu.state.eoi_scheduled) MPU401_EOIHandler();
00572 }
00573 
00574 //Updates counters and requests new data on "End of Input"
00575 static void MPU401_EOIHandler(Bitu val) {
00576     (void)val;//UNUSED
00577         mpu.state.eoi_scheduled=false;
00578         if (mpu.state.send_now) {
00579                 mpu.state.send_now=false;
00580                 if (mpu.state.cond_req) UpdateConductor();
00581                 else UpdateTrack(mpu.state.channel);
00582         }
00583         mpu.state.irq_pending=false;
00584         if (!mpu.state.playing || !mpu.state.req_mask) return;
00585         Bitu i=0;
00586         do {
00587                 if (mpu.state.req_mask&(1<<i)) {
00588                         QueueByte(0xf0+i);
00589                         mpu.state.req_mask&=~(1<<i);
00590                         break;
00591                 }
00592         } while ((i++)<16);
00593 }
00594 
00595 static void MPU401_ResetDone(Bitu) {
00596         mpu.state.reset=false;
00597         if (mpu.state.cmd_pending) {
00598                 MPU401_WriteCommand(0x331,mpu.state.cmd_pending-1,1);
00599                 mpu.state.cmd_pending=0;
00600         }
00601 }
00602 static void MPU401_Reset(void) {
00603         PIC_DeActivateIRQ(mpu.irq);
00604         mpu.mode=(mpu.intelligent ? M_INTELLIGENT : M_UART);
00605         PIC_RemoveEvents(MPU401_EOIHandler);
00606         mpu.state.eoi_scheduled=false;
00607         mpu.state.wsd=false;
00608         mpu.state.wsm=false;
00609         mpu.state.conductor=false;
00610         mpu.state.cond_req=false;
00611         mpu.state.cond_set=false;
00612         mpu.state.playing=false;
00613         mpu.state.run_irq=false;
00614         mpu.state.irq_pending=false;
00615         mpu.state.cmask=0xff;
00616         mpu.state.amask=mpu.state.tmask=0;
00617         mpu.state.midi_mask=0xffff;
00618         mpu.state.data_onoff=0;
00619         mpu.state.command_byte=0;
00620         mpu.state.block_ack=false;
00621         mpu.clock.tempo=mpu.clock.old_tempo=100;
00622         mpu.clock.timebase=mpu.clock.old_timebase=120;
00623         mpu.clock.tempo_rel=mpu.clock.old_tempo_rel=0x40;
00624         mpu.clock.tempo_grad=0;
00625         mpu.clock.clock_to_host=false;
00626         mpu.clock.cth_rate=60;
00627         mpu.clock.cth_counter=0;
00628         ClrQueue();
00629         mpu.state.req_mask=0;
00630         mpu.condbuf.counter=0;
00631         mpu.condbuf.type=T_OVERFLOW;
00632         for (Bitu i=0;i<8;i++) {mpu.playbuf[i].type=T_OVERFLOW;mpu.playbuf[i].counter=0;}
00633 }
00634 
00635 static void IMF_Write(Bitu port,Bitu val,Bitu iolen) {
00636     (void)iolen;//UNUSED
00637         LOG(LOG_MISC,LOG_NORMAL)("IMF:Wr %4X,%X",(int)port,(int)val);
00638 }
00639 
00640 class MPU401:public Module_base{
00641 private:
00642         IO_ReadHandleObject ReadHandler[2];
00643         IO_WriteHandleObject WriteHandler[2];
00644         bool installed; /*as it can fail to install by 2 ways (config and no midi)*/
00645 public:
00646         MPU401(Section* configuration):Module_base(configuration){
00647                 installed = false;
00648                 Section_prop * section=static_cast<Section_prop *>(configuration);
00649                 const char* s_mpu = section->Get_string("mpu401");
00650                 if(strcasecmp(s_mpu,"none") == 0) return;
00651                 if(strcasecmp(s_mpu,"off") == 0) return;
00652                 if(strcasecmp(s_mpu,"false") == 0) return;
00653                 if (!MIDI_Available()) return;
00654                 /*Enabled and there is a Midi */
00655                 installed = true;
00656 
00657         if (IS_PC98_ARCH) {
00658             // NTS: This is based on MMD.COM I/O probing behavior
00659             WriteHandler[0].Install(0xE0D0,&MPU401_WriteData,IO_MB);
00660             WriteHandler[1].Install(0xE0D2,&MPU401_WriteCommand,IO_MB);
00661             ReadHandler[0].Install(0xE0D0,&MPU401_ReadData,IO_MB);
00662             ReadHandler[1].Install(0xE0D2,&MPU401_ReadStatus,IO_MB);
00663         }
00664         else {
00665             WriteHandler[0].Install(0x330,&MPU401_WriteData,IO_MB);
00666             WriteHandler[1].Install(0x331,&MPU401_WriteCommand,IO_MB);
00667             ReadHandler[0].Install(0x330,&MPU401_ReadData,IO_MB);
00668             ReadHandler[1].Install(0x331,&MPU401_ReadStatus,IO_MB);
00669             /*
00670                IO_RegisterWriteHandler(0x280,&IMF_Write,IO_MB);
00671                IO_RegisterWriteHandler(0x281,&IMF_Write,IO_MB);
00672                IO_RegisterReadHandler(0x280,&IMF_Read,IO_MB);
00673                IO_RegisterReadHandler(0x281,&IMF_Read,IO_MB);
00674                */
00675             /*
00676                IO_RegisterWriteHandler(0x200,&IMF_Write,IO_MB);
00677                IO_RegisterWriteHandler(0x201,&IMF_Write,IO_MB);
00678                IO_RegisterWriteHandler(0x202,&IMF_Write,IO_MB);
00679                IO_RegisterWriteHandler(0x203,&IMF_Write,IO_MB);
00680                IO_RegisterWriteHandler(0x204,&IMF_Write,IO_MB);
00681 
00682                IO_RegisterReadHandler(0x200,&IMF_Read,IO_MB);
00683                IO_RegisterReadHandler(0x201,&IMF_Read,IO_MB);
00684                IO_RegisterReadHandler(0x202,&IMF_Read,IO_MB);
00685                IO_RegisterReadHandler(0x203,&IMF_Read,IO_MB);
00686                IO_RegisterReadHandler(0x204,&IMF_Read,IO_MB);
00687                */
00688             IO_RegisterWriteHandler(0x2A20,&IMF_Write,IO_MB);
00689             IO_RegisterWriteHandler(0x2A21,&IMF_Write,IO_MB);
00690             IO_RegisterWriteHandler(0x2A22,&IMF_Write,IO_MB);
00691             IO_RegisterWriteHandler(0x2A23,&IMF_Write,IO_MB);
00692             IO_RegisterWriteHandler(0x2A24,&IMF_Write,IO_MB);
00693             IO_RegisterWriteHandler(0x2A25,&IMF_Write,IO_MB);
00694             IO_RegisterWriteHandler(0x2A26,&IMF_Write,IO_MB);
00695             IO_RegisterWriteHandler(0x2A27,&IMF_Write,IO_MB);
00696             IO_RegisterWriteHandler(0x2A28,&IMF_Write,IO_MB);
00697             IO_RegisterWriteHandler(0x2A29,&IMF_Write,IO_MB);
00698             IO_RegisterWriteHandler(0x2A2A,&IMF_Write,IO_MB);
00699             IO_RegisterWriteHandler(0x2A2B,&IMF_Write,IO_MB);
00700             IO_RegisterWriteHandler(0x2A2C,&IMF_Write,IO_MB);
00701             IO_RegisterWriteHandler(0x2A2D,&IMF_Write,IO_MB);
00702             IO_RegisterWriteHandler(0x2A2E,&IMF_Write,IO_MB);
00703             IO_RegisterWriteHandler(0x2A2F,&IMF_Write,IO_MB);
00704         }
00705 
00706                 mpu.queue_used=0;
00707                 mpu.queue_pos=0;
00708                 mpu.mode=M_UART;
00709 
00710         if (IS_PC98_ARCH)
00711             mpu.irq=5;  /* So far this seems to be the IRQ that games expect it to be at */
00712         else
00713                 mpu.irq=9;      /* Princess Maker 2 wants it on irq 9 */
00714 
00715         {
00716             int x = section->Get_int("mpuirq");
00717 
00718             if (x >= 2)
00719                 mpu.irq = (unsigned int)x;
00720 
00721             if (!IS_PC98_ARCH && mpu.irq == 2) mpu.irq = 9;
00722         }
00723 
00724         LOG(LOG_MISC,LOG_NORMAL)("MPU IRQ %d",(int)mpu.irq);
00725 
00726                 mpu.intelligent = true; //Default is on
00727                 if(strcasecmp(s_mpu,"uart") == 0) mpu.intelligent = false;
00728                 if (!mpu.intelligent) return;
00729                 /*Set IRQ and unmask it(for timequest/princess maker 2) */
00730                 PIC_SetIRQMask(mpu.irq,false);
00731                 MPU401_Reset();
00732         }
00733 };
00734 
00735 static MPU401* test = NULL;
00736 
00737 void MPU401_Destroy(Section* sec){
00738     (void)sec;//UNUSED
00739         if (test != NULL) {
00740                 delete test;
00741                 test = NULL;
00742         }
00743 }
00744 
00745 void MPU401_Reset(Section* sec) {
00746     (void)sec;//UNUSED
00747         if (test == NULL) {
00748                 LOG(LOG_MISC,LOG_DEBUG)("Allocating MPU401 emulation");
00749                 test = new MPU401(control->GetSection("midi"));
00750         }
00751 }
00752 
00753 void MIDI_GUI_OnSectionPropChange(Section *x);
00754 
00755 void MIDI_OnSectionPropChange(Section *x) {
00756     delete test;
00757     test = NULL;
00758 
00759     LOG(LOG_MISC,LOG_DEBUG)("Resetting MPU401, config change");
00760 
00761     MIDI_GUI_OnSectionPropChange(x);
00762 
00763     test = new MPU401(control->GetSection("midi"));
00764 }
00765 
00766 void MPU401_Init() {
00767         LOG(LOG_MISC,LOG_DEBUG)("Initializing MPU401 emulation");
00768 
00769         AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(MPU401_Reset));
00770         AddExitFunction(AddExitFunctionFuncPair(MPU401_Destroy),true);
00771 
00772         control->GetSection("midi")->onpropchange.push_back(&MIDI_OnSectionPropChange);
00773 }
00774