⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mfi.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (length > infoLength)			break;		infoLength -= length;		if (type == BE_FCC(0x7469746C /*titl*/))		{			char				*title;						if (length == 0)				return NULL;			if ((title = malloc(length + 1)) == NULL)				break;			if (tf_read(title, length, 1, tf) != 1)			{				free(title);				break;			}			title[length] = '\0';			return title;		}		else if (length != 0 && tf_seek(tf, length, SEEK_CUR) == -1)			break;	}	return NULL;}typedef struct LastNoteInfo {	int				on, off, note, velocity;} LastNoteInfo;#define NO_LAST_NOTE_INFO	-1#define LASTNOTEINFO_HAS_DATA(lni)	((lni).on != NO_LAST_NOTE_INFO)#define SEND_LASTNOTEINFO(lni, ch)				if (LASTNOTEINFO_HAS_DATA((lni)[ch])) SendLastNoteInfo(lni, ch);#define SEND_AND_CLEAR_LASTNOTEINFO(lni, ch)	if (LASTNOTEINFO_HAS_DATA((lni)[ch])) { SendLastNoteInfo(lni, ch); (lni)[ch].on = NO_LAST_NOTE_INFO; }inline void StoreLastNoteInfo(LastNoteInfo *info, int channel, int time, int duration, int note, int velocity){	info[channel].on = time;	info[channel].off = time + duration;	info[channel].note = note;	info[channel].velocity = velocity;}inline void SendLastNoteInfo(const LastNoteInfo *info, int channel){	NOTE_BUF_EV_DEBUGSTR(channel, info[channel].on, note_name[info[channel].note % 12], info[channel].note / 12, info[channel].velocity, info[channel].off);	MIDIEVENT(info[channel].on, ME_NOTEON, channel, info[channel].note, info[channel].velocity);	MIDIEVENT(info[channel].off, ME_NOTEOFF, channel, info[channel].note, 0);}#define CHECK_AND_READ_FROM_FILE(ptr, readLen)		do {	\						if ((length) < (readLen) || tf_read(ptr, readLen, 1, tf) != 1) {	\							ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Odd track length.");	\							return 1;	\						}	\						length -= readLen;	\					} while(0)static int read_mfi_track(int trackNo, int length, int mfiVersion, int noteType, int extStDLength, timidity_file *tf){	uint8				data[5];	int					i, pos, note, velocity, dataLength;	uint8				instruments[MAX_CHANNELS];	int					channelMap[4];	LastNoteInfo		lastNotes[MAX_CHANNELS];		readmidi_set_track(trackNo, 1);	pos = 0;	velocity = 0x7F;	for(i = 0; i < 4; i++)		channelMap[i] = (trackNo * 4) + i;	dataLength = (noteType == 1) ? 4 : 3;	data[3] = 0;	/* initialize for debugging purpose */	for(i = 0; i < MAX_CHANNELS; i++)		lastNotes[i].on = NO_LAST_NOTE_INFO;	while (length > 0)	{		CHECK_AND_READ_FROM_FILE(data, dataLength);		pos += data[0];		if (data[1] != 0xFF)	/* note */		{			int					channel;						channel = channelMap[data[1] >> 6];			note = 0x48 - 0x1B + (data[1] & 0x3F);			if (dataLength >= 4)			{				velocity = ((data[3] & 0xFC) >> 1) | (data[3] >> 7);	/* abcdefgh -> 0abcdefa */				if (data[3] & 0x2)		/* sign */					data[3] |= ~0x01;				else					data[3] &= 0x01;				note += ((int8)data[3]) * 12;	/* octave shift */			}			if (LASTNOTEINFO_HAS_DATA(lastNotes[channel]))			{				if (lastNotes[channel].off <= pos						|| note != lastNotes[channel].note)				{					SendLastNoteInfo(lastNotes, channel);					StoreLastNoteInfo(lastNotes, channel, pos, data[2], note, velocity);				}				#if 0				else if (note != lastNotes[channel].note)	/* possible slur */				{					if (lastNotes[channel].on == pos)	/* may be a chord */					{						SendLastNoteInfo(lastNotes, channel);						StoreLastNoteInfo(lastNotes, channel, pos, data[2], note, velocity);					}					else	/* slur */					{						/* not implemented */					}				}				#endif				else	/* tie, what if the velocity isn't the same? :-) */					lastNotes[channel].off = pos + data[2];			}			else				StoreLastNoteInfo(lastNotes, channel, pos, data[2], note, velocity);			NOTE_EVENT_DEBUGSTR(channel, note_name[note % 12], note / 12, velocity, data[2]);		}		else	/* controls */		{			if (dataLength == 3)				CHECK_AND_READ_FROM_FILE(&data[3], 1);			if ((data[2] & 0xF0) == 0xC0)	/* tempo */			{				int				timebase, tempo;								timebase = data[2] & 0xF;				if ((timebase & 0x7) == 0x7)					ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Undefined tempo timebase.");				else				{					if (timebase & 0x8)						timebase = 15 << (timebase & 0x7);					else						timebase = 6 << (timebase & 0x7);					tempo = 48 * (1000000 * 60 / data[3] / timebase);					MIDIEVENT(pos, ME_TEMPO, tempo & 0xFF, (tempo >> 16) & 0xFF, (tempo >> 8) & 0xFF);				}			}			else if ((data[2] & 0xF0) == 0xF0)	/* extended controls */			{				int				extLength, channel;				uint8			extData[512];								CHECK_AND_READ_FROM_FILE(&data[4], 1);				extLength = (data[3] << 8) | data[4];				if (extLength <= sizeof extData)				{					CHECK_AND_READ_FROM_FILE(extData, extLength);					switch(data[2] & 0xF)					{						/* case 0x0:	/-* modify envelope (MFi1) */						case 0x1:	/* vibrato (MFi1) */							if (mfiVersion == 1 && extData[0] == 0x01 && extData[1] & 0x01)							{								channel = channelMap[extData[1] >> 5];								MIDIEVENT(pos, ME_MODULATION_WHEEL, channel, (extData[2] & 0xC0) ? 64 : 0, 0)							}							break;						/*case 0xF:	/-* system exclusive (MFi2 or MFi3) */						default:							EX_UNKNOWN_EXT_DATA_DEBUGSTR(extLength);					}				}				else				{					if (tf_seek(tf, extLength, SEEK_CUR) == -1)						return 1;					EX_UNKNOWN_EXT_DATA_DEBUGSTR(extLength);					length -= extLength;				}			}			else			{				int				part, channel, value;				#define GET_PART_AND_CHANNEL(p, c)		(p) = data[3] >> 6; (c) = channelMap[p]								switch(data[2])				{					case 0xB0:	/* master volume */						value = MAPBITS2(data[3] & 0x7F, 7, 16);						MIDIEVENT(pos, ME_MASTER_VOLUME, 0, value & 0xFF, value >> 8);						EX_NCDATA_DEBUGSTR1("Master Volume", "%d", value);						break;					case 0xBA:	/* set drum channel flag */						channel = (data[3] >> 3) & 0xF;						value = data[3] & 0x1;						MIDIEVENT(pos, ME_DRUMPART, channel, value, 0);						EX_DATA_DEBUGSTR1("Drum Flag", channel, "%d", value);						break;					case 0xD0:	/* music begin/end */						/* ignored */						break;					/* case 0xDD:	/-* loop begin/end */					case 0xDE:	/* nop */						break;					case 0xDF:	/* end-of-track */						if (length != 0)						{							ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Premature end-of-track (%d)", length);							length = 0;						}						break;					case 0xE0:	/* program change */						GET_PART_AND_CHANNEL(part, channel);						SEND_AND_CLEAR_LASTNOTEINFO(lastNotes, channel);						/*MIDIEVENT(pos, ME_DRUMPART, channel, 0, 0);*/						instruments[channel] = (instruments[channel] & 0x40) | (data[3] & 0x3F);						MIDIEVENT(pos, ME_PROGRAM, channel, instruments[channel], 0);						EX_DATA_DEBUGSTR1("Program Change", channel, "%d", instruments[channel]);						break;					case 0xE1:	/* pre program change */						GET_PART_AND_CHANNEL(part, channel);						instruments[channel] = (data[3] & 0x1) << 6;						EX_DATA_DEBUGSTR1("Pre Program Change", channel, "%d", instruments[channel]);						break;					case 0xE2:	/* volume */						GET_PART_AND_CHANNEL(part, channel);						value = MAPBITS(data[3] & 0x3F, 6, 7);						MIDIEVENT(pos, ME_MAINVOLUME, channel, value, 0);						EX_DATA_DEBUGSTR1("Volume", channel, "%d", value);						break;					case 0xE3:	/* pan */						GET_PART_AND_CHANNEL(part, channel);						value = MAPBITS(data[3] & 0x3F, 6, 7);						MIDIEVENT(pos, ME_PAN, channel, value, 0);						EX_DATA_DEBUGSTR1("Pan", channel, "%d", value);						break;					case 0xE4:	/* pitch bend (MFi3) */						if (mfiVersion >= 3)						{							GET_PART_AND_CHANNEL(part, channel);							value = MAPBITS2(data[3] & 0x3F, 6, 14);							MIDIEVENT(pos, ME_PITCHWHEEL, channel, value & 0x7F, value >> 7);							EX_DATA_DEBUGSTR1("Pitch Bend", channel, "%d", value);						}						break;					case 0xE5:	/* map part to channel */						part = data[3] >> 6;						SEND_AND_CLEAR_LASTNOTEINFO(lastNotes, channelMap[part]);						channelMap[part] = data[3] & 0xF;						SEND_AND_CLEAR_LASTNOTEINFO(lastNotes, channelMap[part]);						EX_DATA_DEBUGSTR1("Map Channel", part, "%d", channelMap[part]);						break;					case 0xE6:	/* expression */						GET_PART_AND_CHANNEL(part, channel);						value = data[3] & 0x3F;						if (value & 0x20)							value = 64 - (((value ^ 0x3F) + 1) << 1);						else if (value & 0x10)							value = 64 + 1 + (value << 1);						else							value = 64 + (value << 1);						MIDIEVENT(pos, ME_EXPRESSION, channel, value, 0);						EX_DATA_DEBUGSTR1("Expression", channel, "%d", value);						break;					case 0xE7:	/* pitch bend range (MFi3) */						if (mfiVersion >= 3)						{							GET_PART_AND_CHANNEL(part, channel);							value = data[3] & 0x3F;							MIDIEVENT(pos, ME_RPN_MSB, channel, 0, 0);							MIDIEVENT(pos, ME_RPN_LSB, channel, 0, 0);							MIDIEVENT(pos, ME_DATA_ENTRY_MSB, channel, value, 0);							EX_DATA_DEBUGSTR1("Pitch Bend Range", channel, "%d", value);						}						break;					case 0xEA:	/* vibrato (MFi3) */						if (mfiVersion >= 3)						{							GET_PART_AND_CHANNEL(part, channel);							value = MAPBITS(data[3] & 0x3F, 6, 7);							MIDIEVENT(pos, ME_MODULATION_WHEEL, channel, value, 0);							EX_DATA_DEBUGSTR1("Vibrato", channel, "%d", value);						}						break;					default:						EX_UNKNOWN_DATA_DEBUGSTR();				}			}		}	}	for(i = 0; i < MAX_CHANNELS; i++)	{		SEND_LASTNOTEINFO(lastNotes, i);	}	return 0;}static int tf_read_beint16(int *value, timidity_file *tf){	uint16				value_;		if (tf_read(&value_, 2, 1, tf) != 1)		return 0;	*value = BE_SHORT(value_);	return 1;}static int tf_read_beint32(int *value, timidity_file *tf){	uint32				value_;		if (tf_read(&value_, 4, 1, tf) != 1)		return 0;	*value = BE_LONG(value_);	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -