//Updates counters and requests new data on "End of Input" static void MPU401_EOIHandler(void *p) { mpu_t *mpu = (mpu_t *)p; uint8_t i; pclog("MPU-401 end of input callback\n"); mpu401_eoi_callback = 0; mpu->state.eoi_scheduled=0; if (mpu->state.send_now) { mpu->state.send_now=0; if (mpu->state.cond_req) UpdateConductor(mpu); else UpdateTrack(mpu, mpu->state.channel); } mpu->state.irq_pending=0; if (!mpu->state.playing || !mpu->state.req_mask) return; i=0; do { if (mpu->state.req_mask&(1<<i)) { QueueByte(mpu, 0xf0+i); mpu->state.req_mask&=~(1<<i); break; } } while ((i++)<16); }
void CTextReader::EnsureResolution(Resolution resRequired) { // Do we already have the required resolution? if (_res <= resRequired) return; // No data is the easy case if (_dataLength==0) { _res = resRequired; return; } // Steal the current buffer int oldDataLength = _dataLength; unsigned char* oldBuffer = _buffer; // Allocate a new one InitBuffer(); // Switch resolution Resolution oldResolution = _res; _res = resRequired; switch (oldResolution) { case resBytes: for (int i=0; i<oldDataLength; i++) { QueueByte(oldBuffer[i]); } break; case resBits: for (int i=0; i<oldDataLength; i++) { QueueBit(oldBuffer[i]); } break; default: assert(false); } // And clean up free(oldBuffer); }
//Updates counters and requests new data on "End of Input" void MPU401_EOIHandler(void) { Bit8u i=0; /* SOFTMPU */ mpu.state.eoi_scheduled=false; if (mpu.state.send_now) { mpu.state.send_now=false; if (mpu.state.cond_req) UpdateConductor(); else UpdateTrack(mpu.state.channel); } mpu.state.irq_pending=false; if (!mpu.state.playing || !mpu.state.req_mask) return; do { if (mpu.state.req_mask&(1<<i)) { QueueByte(0xf0+i); mpu.state.req_mask&=~(1<<i); break; } } while ((i++)<16); }
bool CTextReader::Open(const char* filename, Resolution res) { _res = res; // Open the file FILE* file=fopen(filename,"rt"); if (file==NULL) { fprintf(stderr, "Could not open '%s' - %s (%i)\n", filename, strerror(errno), errno); return false; } // Parse the file parseState state = psReady; int ch; int pos=-1; bool ReadNextChar = true; int data; char buf[512]; int bufPos=0; while ( !ReadNextChar || ((ch=fgetc(file)) >= 0) ) { ReadNextChar = true; pos++; switch (state) { case psReady: switch (ch) { case '[': state = psComment; bufPos=0; break; case '/': state = psSlash; break; case '0': state = psLeadingZero; break; case '1': QueueBit(1); break; case 'S': case 'L': case '?': case '<': case '>': QueueCycleKind(ch); break; case ' ': case '\t': case '\n': case '\r': break; default: fprintf(stderr, "Error parsing input text file, unexpected character '%c' at %i\n", (char)ch, pos); fclose(file); return false; } break; case psComment: if (ch==']') { state = psReady; // Data format comment? if (strncmp(buf, "format:", 7)==0) { strcpy(_dataFormat, buf+7); } } else { if (bufPos+1 < sizeof(buf)) { buf[bufPos++]=ch; buf[bufPos]='\0'; } } break; case psSlash: if (ch=='/') state = psComment; else { fprintf(stderr, "Error parsing input text file, unexpected character '%c' at %i\n", (char)ch, pos); fclose(file); return false; } break; case psLineComment: if (ch=='\r' || ch=='\n') { state = psReady; } break; case psLeadingZero: if (ch=='x') { state = psHexHi; } else { QueueBit(0); state = psReady; ReadNextChar = false; } break; case psHexHi: case psHexLo: int nib = HexToInt(ch); if (nib<0) { fprintf(stderr, "Error parsing input text file, syntax error in hex byte unexpected '%c' at %i\n", (char)ch, pos); fclose(file); return false; } if (state==psHexHi) { data = nib << 4; state = psHexLo; } else { data |= nib; QueueByte(data); state = psReady; } break; } } fclose(file); if (state != psReady) { fprintf(stderr, "Error parsing input text file, unexpected EOF\n"); return false; } // All good return true; }
void MPU401_WriteData(Bit8u val) { /* SOFTMPU */ static Bit8u length,cnt,posd; /* SOFTMPU */ if (mpu.mode==M_UART) {MIDI_RawOutByte(val);return;} switch (mpu.state.command_byte) { /* 0xe# command data */ case 0x00: break; case 0xe0: /* Set tempo */ mpu.state.command_byte=0; mpu.clock.tempo=val; return; case 0xe1: /* Set relative tempo */ mpu.state.command_byte=0; /*if (val!=0x40) //default value LOG(LOG_MISC,LOG_ERROR)("MPU-401:Relative tempo change not implemented");*/ /* SOFTMPU */ return; case 0xe7: /* Set internal clock to host interval */ mpu.state.command_byte=0; mpu.clock.cth_rate=val>>2; return; case 0xec: /* Set active track mask */ mpu.state.command_byte=0; mpu.state.tmask=val; return; case 0xed: /* Set play counter mask */ mpu.state.command_byte=0; mpu.state.cmask=val; return; case 0xee: /* Set 1-8 MIDI channel mask */ mpu.state.command_byte=0; mpu.state.midi_mask&=0xff00; mpu.state.midi_mask|=val; return; case 0xef: /* Set 9-16 MIDI channel mask */ mpu.state.command_byte=0; mpu.state.midi_mask&=0x00ff; mpu.state.midi_mask|=((Bit16u)val)<<8; return; //case 0xe2: /* Set graduation for relative tempo */ //case 0xe4: /* Set metronome */ //case 0xe6: /* Set metronome measure length */ case 0xfe: /* Config byte */ mpu.state.command_byte=0; mpu.config=val; MPU401_Init(); QueueByte(MSG_MPU_ACK); return; default: mpu.state.command_byte=0; return; } if (mpu.state.wsd) { /* Directly send MIDI message */ if (mpu.state.wsd_start) { mpu.state.wsd_start=0; cnt=0; switch (val&0xf0) { case 0xc0:case 0xd0: mpu.playbuf[mpu.state.channel].value[0]=val; length=2; break; case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0: mpu.playbuf[mpu.state.channel].value[0]=val; length=3; break; case 0xf0: /*LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal WSD byte");*/ /* SOFTMPU */ mpu.state.wsd=0; mpu.state.channel=mpu.state.old_chan; return; default: /* MIDI with running status */ cnt++; MIDI_RawOutByte(mpu.playbuf[mpu.state.channel].value[0]); } } if (cnt<length) {MIDI_RawOutByte(val);cnt++;} if (cnt==length) { mpu.state.wsd=0; mpu.state.channel=mpu.state.old_chan; } return; } if (mpu.state.wsm) { /* Directly send system message */ if (val==MSG_EOX) {MIDI_RawOutByte(MSG_EOX);mpu.state.wsm=0;return;} if (mpu.state.wsd_start) { mpu.state.wsd_start=0; cnt=0; switch (val) { case 0xf2:{ length=3; break;} case 0xf3:{ length=2; break;} case 0xf6:{ length=1; break;} case 0xf0:{ length=0; break;} default: length=0; } } if (!length || cnt<length) {MIDI_RawOutByte(val);cnt++;} if (cnt==length) mpu.state.wsm=0; return; } if (mpu.state.cond_req) { /* Command */ switch (mpu.state.data_onoff) { case -1: return; case 0: /* Timing byte */ mpu.condbuf.vlength=0; if (val<0xf0) mpu.state.data_onoff++; else { mpu.state.data_onoff=-1; MPU401_EOIHandlerDispatch(); return; } if (val==0) mpu.state.send_now=true; else mpu.state.send_now=false; mpu.condbuf.counter=val; break; case 1: /* Command byte #1 */ mpu.condbuf.type=T_COMMAND; if (val==0xf8 || val==0xf9) mpu.condbuf.type=T_OVERFLOW; mpu.condbuf.value[mpu.condbuf.vlength]=val; mpu.condbuf.vlength++; if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(); else mpu.state.data_onoff++; break; case 2:/* Command byte #2 */ mpu.condbuf.value[mpu.condbuf.vlength]=val; mpu.condbuf.vlength++; MPU401_EOIHandlerDispatch(); break; } return; } switch (mpu.state.data_onoff) { /* Data */ case -1: return; case 0: /* Timing byte */ if (val<0xf0) mpu.state.data_onoff=1; else { mpu.state.data_onoff=-1; MPU401_EOIHandlerDispatch(); return; } if (val==0) mpu.state.send_now=true; else mpu.state.send_now=false; mpu.playbuf[mpu.state.channel].counter=val; break; case 1: /* MIDI */ mpu.playbuf[mpu.state.channel].vlength++; posd=mpu.playbuf[mpu.state.channel].vlength; if (posd==1) { switch (val&0xf0) { case 0xf0: /* System message or mark */ if (val>0xf7) { mpu.playbuf[mpu.state.channel].type=T_MARK; mpu.playbuf[mpu.state.channel].sys_val=val; length=1; } else { /*LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message");*/ /* SOFTMPU */ mpu.playbuf[mpu.state.channel].type=T_MIDI_SYS; mpu.playbuf[mpu.state.channel].sys_val=val; length=1; } break; case 0xc0: case 0xd0: /* MIDI Message */ mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM; length=mpu.playbuf[mpu.state.channel].length=2; break; case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM; length=mpu.playbuf[mpu.state.channel].length=3; break; default: /* MIDI data with running status */ posd++; mpu.playbuf[mpu.state.channel].vlength++; mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM; length=mpu.playbuf[mpu.state.channel].length; break; } } if (!(posd==1 && val>=0xf0)) mpu.playbuf[mpu.state.channel].value[posd-1]=val; if (posd==length) MPU401_EOIHandlerDispatch(); } }
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); }