/* =======================================
     　debug command([!],[@])を処理する。
     　同期処理実行後に呼び出すこと。
     　[!] - [!], [@] - [@]で囲まれた
     範囲内のstep timeを0にする。
     　ただし、それだけではplayerの負荷が大きいので
     Bn mm hh   (control change)
     Cn pp      (program change)
     En ll mm   (pitch bend change)
     について最適化を施す。
   ======================================= */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "etc.h"
#include "structs.h"
#include "VarLen.h"


#include "config.h"
void do_debug(UBYTE *MTrk[],const int trks,
		const DWORD debugs, DEBUGDAT *debug,
		DWORD syncs,SYNCDAT *sync);


void eventTableInit(UBYTE *Bn_table[]);
int optsmf2(UBYTE *MTrk, DWORD start, DWORD end, int trkmode);
DWORD stripEvent(UBYTE *MTrk,const UBYTE *MTrk_,DWORD *total_bytes,DWORD now,DWORD start);
inline void setDeltaTo0(UBYTE *MTrk, const UBYTE *MTrk_, DWORD *total_bytes,DWORD delta_bytes);
DWORD getVarLenWithRStatus(UBYTE *MTrk,DWORD *delta_bytes,
							WORD *rstatus,int *nouseRstatus,DWORD *diff);
DWORD killControlChange(UBYTE *MTrk,const UBYTE *MTrk_, WORD rstatus,
						DWORD *total_bytes,DWORD diff, int *nextRstatus);
int fixTable(UBYTE *MTrk, DWORD diff,UBYTE *Bn_table[], UBYTE *nextevent, int nextRstatus);


#define BNCNEN	(128 + 5)

void do_debug(UBYTE *MTrk[],const int trks,
		const DWORD debugs, DEBUGDAT *debug,
		DWORD syncs,SYNCDAT *sync)
{
	DWORD i,j;
	DWORD start,end;
#ifdef __GCC__
	DWORD abstimesort[debugs];
#else
	DWORD *abstimesort;
#endif

#ifndef __GCC__
	abstimesort = (DWORD*)emalloc(sizeof(DWORD) * debugs, "abstimesort");
#endif




	for (j = 0; j < debugs; j++) {		/* 同期を考慮した[!][@]指定の絶対時間の割り出し */
		DWORD reltime = 0;

		for (i = 0; i < syncs; i++) {	/* 以下、同一trkで同期受信してないか探す */
			if (sync[i].trk == debug[j].trk && sync[i].midc >= 0) {
				if ( sync[i].total > debug[j].total) {
					break;
				} else {
					reltime = (sync[i].offset < 0)?		/* 安全装置 */
						0 : sync[i].offset - sync[i].total;
				}
			}
		}
		abstimesort[j] = debug[j].total + reltime;	/* テンポ設定の絶対時間 */
	}

	for (j = 1; j < debugs; j++) {		/* 挿入ソート(安定) */
		DWORD i = j - 1;
		const DWORD key = abstimesort[j];
		const DEBUGDAT key_debug = debug[j];

		while (i >= 0 && abstimesort[i] > key) {
			abstimesort[i + 1] = abstimesort[i];
			debug[i + 1] = debug[i];
			i--;
		}
		abstimesort[i + 1] = key;
		debug[i + 1] = key_debug;
	}



	start = end = 0;
	do {
		while ( !(debug[start].mode & 2) && start < debugs ) {	/* [@]始め 検索 */
			start++;
		}
		end = start;
		if (end < debugs) {
			DWORD End;
			do {
				end++;
			} while ( !(debug[end].mode & 2) && end < debugs );	/* [@]終わり 検索 */
			End = (end < debugs)? abstimesort[end] : 0x7FFFFFFF;

			for (i = 0; i <= trks; i++) {
/* fprintf(stderr,"\n%d: s:%d e:%d  ",i,abstimesort[start], End); */
/* fprintf(stderr,"[%d/%d]",debug[start].trk + 1,i); */
				optsmf2(&MTrk[i][0], abstimesort[start], End, (debug[start].trk + 1 == i)? 1:0 );
			}
			for (j = 0; j < debugs; j++) {
													/* [@]〜[@]の[!]の位置調整 */
				if (abstimesort[start] < abstimesort[j] && abstimesort[j] < End) {
					abstimesort[j] = End;
													/* [@]〜[@]の後の[!]の位置調整 */
				} else if (End <= abstimesort[j]) {
					abstimesort[j] -= End - abstimesort[start];
				}
			}
			debug[start].mode = 0;
			if (end < debugs) {
				debug[end].mode = 0;
			}
		}
		if (start >= debugs) {
			break;
		}
		if ( end == start) {		/* [@]が1個(or奇数個)だけ */
			ZTOMFormatMessage(stderr,"[@]が1個足りないか多すぎます。\n");
		}
		/* start = end + 1; */	/* no mean */
	} while (0);


	start = end = 0;
	do {
		int trk;
		while ( !(debug[start].mode & 1) && start < debugs ) {	/* [!]始め 検索 */
			start++;
		}
		end = start;
		trk = debug[start].trk;
		if (end < debugs) {
			DWORD End;
			do {
				end++;
			} while ( !(debug[end].mode & 2) && end < debugs &&
					  debug[end].trk != trk);					/* [!]終わり 検索 */
			End = (end < debugs)? abstimesort[end] : 0x7FFFFFFF;

/* fprintf(stderr,"Trk:%d ",trk); */

			optsmf2(&MTrk[trk + 1][0], abstimesort[start], abstimesort[end], 1);
			for (j = 0; j < debugs; j++) {
													/* [@]〜[@]の[!]の位置調整 */
				if (abstimesort[start] < abstimesort[j] && abstimesort[j] < End && debug[j].trk == trk) {
					abstimesort[j] = End;
													/* [@]〜[@]の後の[!]の位置調整 */
				} else if (End <= abstimesort[j] && debug[j].trk == trk) {
					abstimesort[j] -= End - abstimesort[start];
				}
			}
			debug[start].mode = 0;
			if (end < debugs) {
				debug[end].mode = 0;
			}
		}
		if (start >= debugs) {
			break;
		}
#ifdef AAA
		if ( end == start) {		/* [!]が1個(or奇数個)だけ */
			ZTOMFormatMessage(stderr,"[!]が1個足りないか多すぎます。\n");
		}
#endif
		/* start = end + 1; */
		/* start++; */	/* no mean */
	} while (0);

}


void eventTableInit(UBYTE *Bn_table[])
{
	int i;

	for (i = 0; i < BNCNEN; i++) {				/* control changeテーブル初期化 */
		Bn_table[i] = NULL;
	}
}



/* =================================================================
     start - end間で...
     1. delta timeはすべて0にする
     2. note on,note offがあればつぶす
     3. 同じコントロールチェンジが出現したら、先に出現した物を潰す
   ================================================================= */

int optsmf2(UBYTE *MTrk, DWORD start, DWORD end, int trkmode)
/* trkmode: [@][!]の送信元トラックか否か */
{
	DWORD now = 0;
	UBYTE *MTrk_ = MTrk;
	WORD  rstatus = 0;
	DWORD total_bytes;
	UBYTE *Bn_table[BNCNEN];
	const UBYTE Cn = 128, En = 128 + 2;
	const char trkend[4] = { 0x00, 0xFF, 0x2F, 0x00 };
	UBYTE *before = MTrk + 8;		/* NULL */

	eventTableInit(Bn_table);

	total_bytes = getDwordAlign(MTrk + 4);
	MTrk += 8;

	if (!memcmp(MTrk,trkend,4)) {		/* NULL track */
		return 1;
	}
/*fprintf(stderr,"start=%d\n",start);*/

/*
fprintf(stderr,"[ ");
for (i = 0; i < 20; i++) {
fprintf(stderr,"%.2x ",*(MTrk + i));
}
*/
	while (now <= start) {				/* [!]開始点まで移動 */
		DWORD delta, FORTHBREAK = 0;

		if (!trkmode && now == start) {	/* add v1.51 */
/* fprintf(stderr,"!"); */
			break;
		}

		before = MTrk;
/* fprintf(stderr,"(%.2x %.2x %.2x %.2x %.2x %.2x)", *MTrk, MTrk[1],MTrk[2],MTrk[3],MTrk[4],MTrk[5] ); */
		MTrk += GetVarLen(MTrk, &delta);
		now += delta;

/*fprintf(stderr,"(%d[",now);*/
		if (*MTrk & 0x80) {
			rstatus = *MTrk++;
		}
		switch (rstatus >> 4) {
			case 0x08:	/* 3 note off */
			case 0x09:	/* 3 note on */
			case 0x0a:	/* 3 polyphonic key pressure */
			case 0x0b:	/* 3 control change */
			case 0x0e:	/* 3 pitch bend change */
/*fprintf(stderr,"%.2X])",rstatus); */
				MTrk += 2;
				break;
			case 0x0c:	/* 2 program change */
			case 0x0d:	/* 2 channel pressure */
/* fprintf(stderr,"[@]"); */
				MTrk += 1;
				break;
			case 0x0f:	/* ? exclusive || meta event */
/* fprintf(stderr,"[X]"); */
				if (rstatus == 0xFF) {	/* meta event */
					const WORD bytes = *(MTrk + 1) + 2;
					if ( *MTrk == 0x2F ) {	/* trk end */
						rstatus = -1;
/*fprintf(stderr,"[FF2f");*/
						return 1;
					}
					MTrk += bytes;
					if (*(MTrk - bytes) == 0x07 && trkmode) {		/* [!] [@] */
						/*FORTHBREAK = 1;*/
						before = MTrk;
					}
				} else if (rstatus == 0xF0) {
					MTrk += (*MTrk + 1);
				} else {
					ZTOMFormatMessage( stderr,"F?(%.2x): error!\n",rstatus );
				}
				break;
			default:
				ZTOMFormatMessage(stderr,"[@%.2X]err\n",rstatus);
				break;
		}
		if (FORTHBREAK) {	/* add v1.51 */
/* fprintf(stderr,"[f]"); */
			break;
		}
	}

/*
fprintf(stderr,"[ ");
for (i = 0; i < 20; i++) {
fprintf(stderr,"%.2x ",*(MTrk + i));
}
*/
/*
fprintf(stderr,"[%.2x %.2x %.2x %.2x %.2x %.2x]", *MTrk, MTrk[1],MTrk[2],MTrk[3],MTrk[4],MTrk[5] );
*/
/* fprintf(stderr,"\nn=%d s=%d e=%d",now,start,end); */
	if (now != start) {					/* 必要ならdelta timeを途中でチョン切る */
/* fprintf(stderr,"[b=%.2X %.2X %.2X] ",*before, *(before+1), *(before+2)); */
/*		MTrk -= stripEvent(before,MTrk_,&total_bytes,now, ((now <= end)? start : end - start)); */
		MTrk -= stripEvent(before,MTrk_,&total_bytes,((now <= end)? now : end), start);
/*デルタタイムから(now - start)を引く*/
/*DWORD stripEvent(*before,*MTrk_,DWORD *total_bytes,DWORD now,DWORD start)*/
/*fprintf(stderr,"[v=%.2X %.2X %.2X] ",*before, *(before+1), *(before+2));*/
	} else {
		/* FF 07 03 5B 40 5D 00 (meta).. */		/* [@] */
		/* テキストイベントを挿入して、now以前のデルタタイムを分離する
		 * ただし、トラック頭で条件成立した場合のみは、
		 * デルタタイムを前でなく後ろに回す
		 */
		UBYTE txtevent[7] = { 0xFF, 0x07, 0x03, '[', '@', ']', 0x00 };
		DWORD dummy;
		UBYTE transsize = 7;

		MTrk = before;
/*fprintf(stderr,"[ %.2x %.2x %.2x %.2x %.2x %.2x]", *MTrk, MTrk[1],MTrk[2],MTrk[3],MTrk[4],MTrk[5] );*/
		MTrk += GetVarLen(MTrk, &dummy);
		if (*MTrk < 0x80) {	/* running statusを使用している */
			transsize++;
		}

		if (start != 0) {
			memmove(MTrk + transsize, MTrk, total_bytes - (MTrk - MTrk_) + 8);	/* 8 for "MTrkNNNN" */
			memcpy(MTrk,txtevent, 7);
			if (transsize == 7 + 1) {
				*(MTrk + 7) = rstatus;
			}
			MTrk += 6;
		} else {					/* add this condition on v1.60 */
			memmove(before + (transsize - 1) + 1, before, total_bytes - (before - MTrk_) + 8);	/* 8 for "MTrkNNNN" */
			*before = 0;						/* delta time == 0 */
			memcpy(before + 1, txtevent, 6);	/* not 7 but 6 */
			if (transsize == 7 + 1) {
				PutVarLen(before + (transsize - 1) + 1, dummy);
				*(before + transsize + 1 + get_VarLen_bytes(dummy)) = rstatus;
			}
			MTrk = before + 7;
		}
		rstatus = 0xFF;

		total_bytes += transsize;
	}

/* fprintf(stderr,"\n----\n"); */
	while (now <= end) {					/* [!]〜[!]内の処理 */
		/* DWORD delta; */
		DWORD delta_bytes;
		const DWORD last_now = now;
		int nouseRstatus = 0;
		UBYTE *before = MTrk;
		UBYTE cc;
		DWORD diff,diff2;
		int tmp, FORTHBREAK = 0;

		if (!trkmode && now == end) {	/* add v1.51 */
/* fprintf(stderr,"[END]\n"); */
			break;
		}

/*fprintf(stderr,"*%.2X",MTrk[1]);*/
/*
if (*(MTrk + 1) >> 4 == 0x0e || *(MTrk + 1) == 0x5b || *(MTrk + 1) == 0x5d || *(MTrk + 1) == 0x5e) {
*/

/* fprintf(stderr,"[ %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x]", *MTrk, MTrk[1],MTrk[2],MTrk[3],MTrk[4],MTrk[5],MTrk[6],MTrk[7],MTrk[8] ); */

/*
}
*/
		now += getVarLenWithRStatus(MTrk,&delta_bytes,&rstatus,&nouseRstatus,&diff);
/* fprintf(stderr,"(%d[%.2X %d %d] ",now,rstatus,delta_bytes,nouseRstatus); */
/* fprintf(stderr,"r%.2X)",rstatus); */
		MTrk += delta_bytes + nouseRstatus;

		/* if (now >= end) { */
			if (now > end) {
/* DWORD var1,var2; */
/* fprintf(stderr,"tm=%d / ",trkmode); */
/* fprintf(stderr,"n:%d ln=%d n-ln:%d e:%d / ",now,last_now, now - last_now,end); */
/* fprintf(stderr,"[B=%.2X %.2X %.2X] ",*before, *(before+1), *(before+2)); */
/* GetVarLen(before,&var1); */
				stripEvent(before,MTrk_,&total_bytes,end,last_now);
/* fprintf(stderr,"[C=%.2X %.2X %.2X] ",*before, *(before+1), *(before+2)); */
/* GetVarLen(before,&var2); */
/* fprintf(stderr,"d=%d / last_n+d=%d\n",var1-var2, last_now + (var2)); */

		/*	} */
		} else {
			switch (rstatus >> 4) {
				case 0x08:	/* 3 note off */
				case 0x09:	/* 3 note on */
					/* 本当はnow==endならset delta to 0, それ以外ならdelete event */
												/* →delete event */
					/* diff2 = */ killControlChange(before, MTrk_, rstatus, &total_bytes, diff + 2, &tmp);
					/* fixTable(before, diff2, Bn_table, ); */	/* del 1.48 */
					MTrk = before;
					break;
				case 0x0a:	/* 3 polyphonic key pressure */
												/* →set delta to 0 */
					setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
					MTrk -= (delta_bytes - 1);
					MTrk += 2;					/* next event */
					break;
				case 0x0b:	/* 3 control change */
					cc = *MTrk++;
/*
fprintf(stderr,"CC=%.2x ",cc);
*/
#ifdef AA
if (cc == 0x78) {
	fprintf(stderr,"ILLEGAL CC! / %x",MTrk - MTrk_);
/*	exit(0);*/
}
#endif
					if (Bn_table[cc]) {
						DWORD diff,diff2;
						int nextRstatus;
#ifdef Aaa
						const DWORD nouseRstatus2 = nouseRstatus;
								/* nouseRstatus2: current MTrk's */
								/* nouseRstatus:  will be killed one */
#endif
/*
						DWORD old_useRstatus2;
*/

/* fprintf(stderr,"m1:%.2x ",*MTrk); */
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
/* fprintf(stderr,"m2:%.2x ",*MTrk); */
						MTrk -= (delta_bytes - 1);
						MTrk++;		/* already +1ed at first */

/*
fprintf(stderr,"mtrk=%.2x %.2x %.2x %.2x ",*MTrk, MTrk[1], MTrk[2], MTrk[3]);
fprintf(stderr,"before=%.2x %.2x %.2x %.2x ",*before, before[1], before[2], before[3]);
*/
						/* 次のイベントはrunning status使ってる? */
						getVarLenWithRStatus(
								before,&delta_bytes,&rstatus,&nouseRstatus,&diff);
						/* 隣のイベントが消える && 次はrunnningstatus onなら */
/* fprintf(stderr,"$%d ",before - Bn_table[cc]); */
						if (!nouseRstatus) {
/*fprintf(stderr,"!");*/
							getVarLenWithRStatus(
								Bn_table[cc],&delta_bytes,&rstatus,&nouseRstatus,&diff);
							if (Bn_table[cc] + (1 + nouseRstatus + 2) == before) {
#ifdef A
								MTrk--;		/* 最後に補正が必要になるので最初にやっちゃう */
#endif
								before--;
/*
fprintf(stderr,"##");
*/
							}
						}
						/* before = ++MTrk; */					/* next event */


															/* 以下、過去のccを抹殺 */
						getVarLenWithRStatus(
								Bn_table[cc],&delta_bytes,&rstatus,&nouseRstatus,&diff);
/*
if (cc == 0x5e) {
fprintf(stderr,"{ %.2x %.2x %.2x %.2x}", *Bn_table[cc], Bn_table[cc][1], Bn_table[cc][2], Bn_table[cc][3]);
}
*/

#ifdef AAA
if(Bn_table[cc][0] != 0) {
fprintf(stderr,"ERR: cc=%.2x %.2x %.2x %.2x %.2x %.2x ",cc,Bn_table[cc][0], Bn_table[cc][1], Bn_table[cc][2], Bn_table[cc][3], Bn_table[cc][4]); 
/*exit(1);*/
}
#endif
/*
old_useRstatus2 = (Bn_table[cc][1] & 0x80)? 0 : 1;
if (old_useRstatus2) {
fprintf(stderr,"!");
}
*/
						diff2 = killControlChange(Bn_table[cc], MTrk_, rstatus, &total_bytes, diff + 2, &nextRstatus);
/*
if (cc == 0x5e) {
fprintf(stderr," (%d %d)\n",diff,diff2);
}
*/
						tmp = fixTable(Bn_table[cc], diff2, Bn_table, Bn_table[cc] + diff + 2, nextRstatus);

#ifdef AAA
if (tmp) {
	fprintf(stderr,"warnBn[%.2x]",cc);
/*exit(1);*/
}
#endif

						MTrk -= diff2;						/* なくなったイベント分ずらす */
/* fprintf(stderr, "d2=%d ",diff2); */
#ifdef AAA
if (tmp) {
fprintf(stderr,"MTrk=%.2x %.2x %.2x %.2x",*MTrk, MTrk[1], MTrk[2], MTrk[3]);
/*exit(1);*/
}
#endif

						/* MTrk -= (1 + nouseRstatus + 2); */
						/* Bn_table[cc] = MTrk - (1 + nouseRstatus + 2); */
						Bn_table[cc] = before - diff2;
#ifdef AAA
if(Bn_table[cc][0] != 0) {
fprintf(stderr,"INITERR: cc=%.2x/d=%d/%.2x %.2x %.2x %.2x %.2x ",cc,diff2,Bn_table[cc][0], Bn_table[cc][1], Bn_table[cc][2], Bn_table[cc][3], Bn_table[cc][4]); 
fprintf(stderr,"\nMTrk=%.2x %.2x %.2x %.2x %.2x ",MTrk[0], MTrk[1], MTrk[2], MTrk[3],MTrk[4]);
/*exit(1);*/
} else {
/*
fprintf(stderr,"cc=%.2x ",cc);
*/
}
#endif
/*
fprintf(stderr,"cc=%.2x/d=%d/%.2x %.2x %.2x %.2x %.2x ",cc,diff2,Bn_table[cc][0], Bn_table[cc][1], Bn_table[cc][2], Bn_table[cc][3], Bn_table[cc][4]); 
fprintf(stderr,"\nMTrk=%.2x %.2x %.2x %.2x %.2x ",MTrk[0], MTrk[1], MTrk[2], MTrk[3],MTrk[4]);
*/

															/* 今のイベント開始位置を新たに登録 */
					} else {
/* fprintf(stderr,"cc=%.2x ",cc); */
/* fprintf(stderr,"m0:%.2x_%.2x_%.2x_%.2x ",*MTrk,MTrk[1],MTrk[2],MTrk[3]); */
						Bn_table[cc] = before;
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
						MTrk -= (delta_bytes - 1);
						MTrk++;
#ifdef AAA
if (Bn_table[cc]  && Bn_table[cc][0] != 0) {
	fprintf(stderr,"INITerr %.2x",cc);
/*exit(1);*/
}
#endif
					}
					break;
				case 0x0e:	/* 3 pitch bend change */
					if (Bn_table[En]) {
						int nextRstatus;
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
						MTrk -= (delta_bytes - 1);
						MTrk += 2;							/* next event */
															/* 以下、過去のccを抹殺 */

						/* 次のイベントはrunning status使ってる? */
						getVarLenWithRStatus(
								before,&delta_bytes,&rstatus,&nouseRstatus,&diff);
						/* 隣のイベントが消える && 次はrunnningstatus onなら */
						if (!nouseRstatus) {
							getVarLenWithRStatus(
								Bn_table[En],&delta_bytes,&rstatus,&nouseRstatus,&diff);
							if (Bn_table[En] + (1 + nouseRstatus + 2) == before) {
#ifdef A
								MTrk--;		/* 最後に補正が必要になるので最初にやっちゃう */
#endif
								before--;
							}
						}


/* fprintf(stderr,"{ %.2x %.2x %.2x %.2x}", *Bn_table[En], Bn_table[En][1], Bn_table[En][2], Bn_table[En][3]); */

						getVarLenWithRStatus(
									Bn_table[En],&delta_bytes,&rstatus,&nouseRstatus,&diff);
/* fprintf(stderr,"%d_%d",delta_bytes, nouseRstatus); */
						diff2 = killControlChange(Bn_table[En], MTrk_, rstatus, &total_bytes, diff + 2, &nextRstatus);
						tmp = fixTable(Bn_table[En], diff2, Bn_table, Bn_table[En] + diff + 2, nextRstatus);
#ifdef AAA
if (tmp) {
	fprintf(stderr,"warnEn[%.2x]",En);
}
#endif
						MTrk -= diff2;						/* なくなったイベント分ずらす */
						/* Bn_table[En] = MTrk - (1 + nouseRstatus + 2); */
						Bn_table[En] = before - diff2;
															/* 今のイベント開始位置を新たに登録 */
					} else {
/* fprintf(stderr,"last: %.2x %.2x %.2x %.2x\n", *before, before[1],before[2],before[3] ); */
						Bn_table[En] = before;
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
/* fprintf(stderr,"last: %.2x %.2x %.2x %.2x\n", *before, before[1],before[2],before[3] ); */
						MTrk -= (delta_bytes - 1);
						MTrk += 2;
/* fprintf(stderr,"last: %.2x %.2x %.2x %.2x\n", *MTrk, MTrk[1],MTrk[2],MTrk[3] ); */
					}
					break;
				case 0x0c:	/* 2 program change */
					if (Bn_table[Cn]) {
						int nextRstatus;
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
						MTrk -= (delta_bytes - 1);
						MTrk++;								/* next event */
						/* before = ++MTrk; */					/* next event */


						/* 次のイベントはrunning status使ってる? */
						getVarLenWithRStatus(
								before,&delta_bytes,&rstatus,&nouseRstatus,&diff);
						/* 隣のイベントが消える && 次はrunnningstatus onなら */
						if (!nouseRstatus) {
							getVarLenWithRStatus(
								Bn_table[Cn],&delta_bytes,&rstatus,&nouseRstatus,&diff);
							if (Bn_table[Cn] + (1 + nouseRstatus + 2) == before) {
#ifdef A
								MTrk--;		/* 最後に補正が必要になるので最初にやっちゃう */
#endif
								before--;
							}
						}

															/* 以下、過去のccを抹殺 */
						getVarLenWithRStatus(
									Bn_table[Cn],&delta_bytes,&rstatus,&nouseRstatus,&diff);
						diff2 = killControlChange(Bn_table[Cn], MTrk_, rstatus, &total_bytes, diff + 1, &nextRstatus);
						fixTable(Bn_table[Cn], diff2, Bn_table, Bn_table[Cn] + diff + 1, nextRstatus);
						MTrk -= diff2;						/* なくなったイベント分ずらす */
						/* Bn_table[Cn] = MTrk - (1 + nouseRstatus + 1); */
						Bn_table[Cn] = before - diff2;
															/* 今のイベント開始位置を新たに登録 */
					} else {
						Bn_table[Cn] = before;
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
						MTrk -= (delta_bytes - 1);
						MTrk++;
					}
					break;
				case 0x0d:	/* 2 channel pressure */
					setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
					MTrk -= (delta_bytes - 1);
					MTrk++;
					break;
				case 0x0f:	/* ? exclusive || meta event */
/* fprintf(stderr,"[FF]"); */
					if (rstatus == 0xFF) {	/* meta event */
						const WORD bytes = *(MTrk + 1) + 2;
/* DWORD var1,var2; */
						if ( *MTrk == 0x2F ) {	/* trk end */
							rstatus = -1;
/* fprintf(stderr,"[ff2f]"); */
						}
						MTrk += bytes;
						if (*(MTrk - bytes) == 0x07 && trkmode) {		/* [!] [@] */
/* fprintf(stderr,"[forthbreak]"); */
/* GetVarLen(before,&var1); */
/* fprintf(stderr,"ln=%d n=%d v1=%d ",last_now, now,var1); */
							/* FORTHBREAK = 1; */
						}
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
/* GetVarLen(before,&var2); */
/* fprintf(stderr,"v2=%d\n",var2); */
						MTrk -= (delta_bytes - 1);
						break;
					} else if (rstatus == 0xF0) {
						MTrk += (*MTrk + 1);
						setDeltaTo0(before, MTrk_, &total_bytes, delta_bytes);
						MTrk -= (delta_bytes - 1);
						break;
					} else {
						ZTOMFormatMessage( stderr,"F?(%.2x): error!\n",rstatus );
					}
					break;
				default:
					ZTOMFormatMessage(stderr,"err_[%.2X]\n",rstatus);
					break;
			}
			if (rstatus < 0) {
				break;
			}
		}
		if (FORTHBREAK) {
			break;
		}
	}
/* fprintf(stderr,"\n====\n"); */
	putDwordAlign(MTrk_ + 4,total_bytes);
	return 0;
}



/* =========================================
     デルタタイムから(now - start)を引く
   ========================================= */

DWORD stripEvent(UBYTE *before,const UBYTE *MTrk_,DWORD *total_bytes,DWORD now,DWORD start)
{
	DWORD old_delta, new_delta;
	DWORD old_delta_bytes, new_delta_bytes;
	DWORD diff;

	GetVarLen(before, &old_delta);
	old_delta_bytes = get_VarLen_bytes(old_delta);
	new_delta = old_delta - (now - start);
	/* new_delta = now - start; */
	new_delta_bytes = get_VarLen_bytes(new_delta);
/* fprintf(stderr,"strip:%d %d %d %d ",old_delta,now,start,new_delta); */
	diff = old_delta_bytes - new_delta_bytes;
/*
fprintf(stderr,"now-start = %d ",now - start);
fprintf(stderr,"before=%p diff=%d totalbytes=%d ",before,diff,*total_bytes);
fprintf(stderr,"tbytes=%d ",*total_bytes - (before - MTrk_ - 8) - diff);
fprintf(stderr,"before - MTrk_ - 8 = %d ",before - MTrk_ - 8);
*/
/*
{
	int i;
	for (i = 0; i < *total_bytes - (before - MTrk_ - 8) - diff; i++) {
	}
}
*/
	if (diff) {
		memmove(before, before + diff, *total_bytes - (before - MTrk_ - 8) - diff);
		*total_bytes -= diff;
	}
/*
fprintf(stderr,"[]");
*/
	PutVarLen(before, new_delta);

	return diff;
}


/* =============================
     デルタタイムを0に変更する
   ============================= */

inline void setDeltaTo0(UBYTE *MTrk, const UBYTE *MTrk_, DWORD *total_bytes,DWORD delta_bytes)
{
	*MTrk++ = 0;
	delta_bytes--;
	/* *total_bytes -= (delta_bytes--); */
	*total_bytes -= delta_bytes;
	memmove(MTrk, MTrk + delta_bytes,
				*total_bytes - (MTrk - MTrk_ - 8) + 1);
}


/* ===========================================================
     デルタタイム,イベント,ランニングステータスの有無 の取得
   =========================================================== */

DWORD getVarLenWithRStatus(UBYTE *MTrk,DWORD *delta_bytes,
							WORD *rstatus,int *nouseRstatus,DWORD *diff)
{
	DWORD delta;

	*nouseRstatus = 0;
	*delta_bytes = GetVarLen(MTrk, &delta);
	MTrk += *delta_bytes;
	if (*MTrk & 0x80) {
		*rstatus = *MTrk;
		*nouseRstatus = 1;
	}
	*diff = *delta_bytes + *nouseRstatus;

	return delta;
}


/* ======================
     イベントを抹消する
     返り値：抹消したバイト数
   ====================== */

DWORD killControlChange(UBYTE *MTrk,const UBYTE *MTrk_, WORD rstatus,
						DWORD *total_bytes,DWORD diff, int *nextRstatus)
{
	UBYTE *MTrk2 = MTrk + diff;
	DWORD secondDelta;

	MTrk2 += GetVarLen(MTrk2,&secondDelta);

#ifdef AAA
if (secondDelta && rstatus >> 4 != 0x9) {
fprintf(stderr,"{KE %.2x %.2x %.2x %.2x}",*(MTrk + diff), *(MTrk + diff + 1), *(MTrk + diff + 2), *(MTrk + diff + 3));
}
#endif
	MTrk += PutVarLen(MTrk, secondDelta);
	if (!(*MTrk2 & 0x80)) {
		*MTrk++ = rstatus;
		*nextRstatus = 1;
	} else {
		*nextRstatus = 0;
	}
									/* ここまで 次イベントのrstatus補完措置 */

/* fprintf(stderr,"\nkilled: %.2x %.2x %.2x %.2x (%d)", *MTrk, MTrk[1],MTrk[2],MTrk[3], MTrk2 - MTrk ); */
	memmove(MTrk, MTrk2, *total_bytes - (MTrk - MTrk_ - 8) - (MTrk2 - MTrk));
/* fprintf(stderr,"last: %.2x %.2x %.2x %.2x\n", *MTrk, MTrk[1],MTrk[2],MTrk[3] ); */
	*total_bytes -= (MTrk2 - MTrk);


/* fprintf(stderr," bytes=$%d\n", MTrk2 - MTrk); */
/* #ifdef Aaa */
	return MTrk2 - MTrk;	/* + st; */
/* #endif */
/*	return diff; */
}


/* ================================================
     イベント抹消後、イベントテーブルの調整をする
	イベント抹消分のポインタずれを調整
   ================================================ */

int fixTable(UBYTE *MTrkBase, DWORD diff,UBYTE *Bn_table[], UBYTE *nextevent, int nextRstatus)
{
	int i, rc = 0;

	for (i = 0; i < BNCNEN - 1; i++) {
		if (MTrkBase < Bn_table[i]) {
			if (Bn_table[i] == nextevent) {
				Bn_table[i] -= (diff + nextRstatus);
			} else {
				Bn_table[i] -= diff;
			}
#ifdef AAA
			if (Bn_table[i] && f) {		/* for supplemented cc.... deltatime must be 0 */
fprintf(stderr,"[w%.2x]",i);
				Bn_table[i]--;
			}
if (Bn_table[i] && *Bn_table[i] != 0) {
	fprintf(stderr,"\nWarn(%.2x) diff=%d / %.2x %.2x %.2x %.2x %.2x\n",i,diff,Bn_table[i][0], Bn_table[i][1], Bn_table[i][2], Bn_table[i][3], Bn_table[i][4]);
	rc = 1;
}
#endif

/*
if (i == 128 + 2) {
fprintf(stderr,"fix: %d",i);
fprintf(stderr,"/ %.2x %.2x %.2x %.2x\n", Bn_table[i][0], Bn_table[i][1], Bn_table[i][2], Bn_table[i][3]);
}
*/
		}


	}
	return rc;
}
