Exemple #1
0
//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);
}
Exemple #3
0
//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;
}
Exemple #5
0
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();
	}
}
Exemple #6
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);
}
Exemple #7
0
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);
}