
//音乐解析播放器

//初始版本: 2012年12月 (在国家计量科学院 昌平分部)

//修改日期: 2013年7月20日 增加非连音效果,各个音之间断开一小段时间

//修改日期: 2014年6月29日 把播放器的通道数改为动态扫描, 可以支持多个通道, 采用数组形式

//修改日期: 2014年11月25日
//本打算上午实现音频播放, 可以一条指令播放多个通道, 一开始想到不把所有的通道集合到同一个数组里, 
//不增加每个通道的字节数(这个是昨天想到的), 而是还是按照目前的各个通道分开, 然后在加一个综合的数组,
//描述通道数目, 以及各个通道的头部(也就是数组名).
//但是目前暂时无法在常量数组中指向一个其他的数组名作为常量(只能是字面常量), 于是写了一个临时的函数,
//用法像是一个数组, 实际是收集通道头部到一个数组中, 然后返回这个数组.
//但是调试了一上午也没行!!!
//中午回来看到那个创客孵化大赛已经报名截止了, 不过还好 有个第二期, 好好准备吧...
//刚才忽然就发现了问题原因了:
//出错的程序:
//void play0( [int16*?] p )
//应该这样定义:
//void play0( [->int16*?] p )

//备注日期: 2015年5月8日
//今天又遇到了一个大问题, 播放不了音乐了, 一播放就死机... 找不到原因, 哎
//怀疑是 合并了 base code 之后, 汇编有问题, 但是仔细检查没问题啊.
//弄了一天, 忽然感觉这个情况好熟悉啊! 想起来了, 可能是堆栈溢出了!!! 于是赶紧把 OS 中的堆栈空间
//从 200 改为 300, 结果一试还是不行! 然后冷静下来想想, 明白了, 是中断堆栈, 每个中断函数的
//堆栈尺寸太小了... 于是找到那个关键的数字, 100改成了200, 一切OK!

//修改日期: 2016年11月27日
//升级了新版播放器协议

unit music
{
	public const uint16 ID = 0;

	//[i] var_uint8 OS_time;
	uint8 OS_time;

	//[i] var_uint8 OS_EventFlag;
	public uint8 OS_EventFlag;
	//[i] event trig1_event;
	//[i] event trig2_event;

	//[i] var_int32 CurrentTone1;
	public int32 CurrentTone1;
	//[i] var_int32 CurrentTone2;
	public int32 CurrentTone2;
	
	const int8 NUMBER = 4;
	[bool*NUMBER] is_play;
	[uint8*NUMBER] breakTime;
	[bool*NUMBER] liaison;
	[int8*NUMBER] volume;
	[uint8*NUMBER] tick_ms_count;
	[uint8*NUMBER] tick_ms;
	[uint8*NUMBER] time;
	[uint16*NUMBER] index;
	[uint8*NUMBER] offset;
	[->[uint8*?]*NUMBER] music_list;
	
	//[i] linkinterface_tone tone;
	link unit tone {}
	
	int8 Index;
	bool Break;
	
	[uint8*NUMBER] last;
	
	//[i] var_bool isPause;
	bool isPause;
	//[i] var_bool isStop;
	bool isStop;
	
	//---------------------------------------------------
	//[i] function_void OS_init;
	void OS_init()
	{
		OS_time = 1;
		OS_EventFlag = 0;
		
		for( int8 i = 0; i < NUMBER; i + 1 ) {
			is_play[i] = false;
			tick_ms_count[i] = 0;
			tick_ms[i] = 20;
			index[i] = 0;
			time[i] = 0;
			volume[i] = 127;
			liaison[i] = false;
			breakTime[i] = 0;
			last[i] = 0;
			offset[i] = 60;
		}
		Index = 0;
		Break = false;
		
		isStop = true;
		isPause = false;
	}
	//---------------------------------------------------
	//[i] function_void play0 music;
	void play0( [uint8*?] p )
	{
		stop();
		uint16 n = p[0];
		n.8(uint8) = p[1];
		for( uint16 i = 0; i < n; i + 1 ) {
			uint16 sn = p[i*2+2];
			sn.8(uint8) = p[i*2+3];
			play( i, p, sn );
		}
		isPause = false;
		isStop = false;
	}
	//---------------------------------------------------
	//[i] function_void stop;
	void stop()
	{
		tone.stop( 0, 0 );
		tone.stop( 1, 0 );
		is_play[0] = false;
		is_play[1] = false;
		isPause = false;
		isStop = true;
	}
	//---------------------------------------------------
	//[i] function_void Pause;
	void Pause()
	{
		isPause = true;
	}
	//---------------------------------------------------
	//[i] function_void Continue;
	void Continue()
	{
		isPause = false;
	}
	//---------------------------------------------------
	void play( uint16 c, [uint8*?] p, uint16 sn )
	{
		volume[c] = 127;
		tick_ms_count[c] = 0;
		tick_ms[c] = 20;
		time[c] = 1;
		music_list[c] -> p;
		index[c] = sn;
		last[c] = 0;
		offset[c] = 60;
		is_play[c] = true;
	}
	//---------------------------------------------------
	//[i] function_void OS_run;
	void OS_run()
	{
		if( isPause ) return;
		
		if( Break ) { Break = false; goto B; }
		for( Index = 0; Index < NUMBER; Index + 1 ) {
			if( is_play[Index] ) {
				//音符最小时值计时
				tick_ms_count[Index] + 1;
				if( tick_ms_count[Index] == tick_ms[Index] ) {
					tick_ms_count[Index] = 0;
					//时值递减,判断时值是否到达
					time[Index] - 1;
					
					//if( time[Index] == 1 ) {
					//	if( last[Index] & 0x80 == 0 ) {
					//		tone.stop( Index + 1, 0 );
					//	}
					//}
					
					if( time[Index] == 0 ) {
						B:
						if( tone.isBusy ) {
							Break = true;
							//tone.isNeed = true;
							return;
						}
						//tone.isNeed = false;
						is_play[Index] = decode(
							Index + 1,
							music_list[Index],
							index[Index],
							time[Index],
							tick_ms[Index],
							volume[Index],
							liaison[Index],
							breakTime[Index],
							last[Index],
							offset[Index]
						);
						isStop = !is_play[0] && !is_play[1];
					}
				}
			}
		}
	}
	//---------------------------------------------------
	//音乐数据解码器
	//解释执行音乐宏指令
	bool decode(
		int8 c,
		[uint8*?] music_list0,
		uint16 index0*,
		uint8 time0*,
		uint8 tick_ms0*,
		int8 vol*,
		bool liaison0*,
		uint8 last0*,
		uint8 breakTime0*,
		uint8 offset0* )
	{
		bool is_play0 = true;
		forever {
			uint8 d = music_list0[index0];
			if( d == 255 ) {
				is_play0 = false;
				tone.stop( c, 0 );
				break;
			}
			if( d == 254 ) {
				index0 + 1;
				offset0 = music_list0[index0];
				index0 + 1;
				tick_ms0 = tone.switch_time( music_list0[index0] );
				index0 + 1;
				continue;
			}
			if( d == 253 ) {
				index0 + 2;
				continue;
			}
			if( d == 127 ) {
				index0 + 1;
				vol = (int)music_list0[index0];
				index0 + 1;
				continue;
			}
			if( d == 126 ) {
				index0 + 2;
				continue;
			}
			d = music_list0[index0];
			
			//连续的两个相同音,加一个隔断延时
			if( last0 == d ) {
				tone.stop( c, 0 );
				loop( 10000 ) {}
			}
			
			if( last0 & 0x80 == 0 || last0 & 0x7F != d & 0x7F ) {
				if( last0 & 0x7F != 0 ) {
					tone.stop( c, 0 );
				}
				if( d & 0x7F != 0 ) {
					tone.play( c, (int)((d & 0x7F) + offset0 - 60), vol );
					if( c == 1 ) {
						OS_EventFlag.0(bit) = 1;
						CurrentTone1 = (int)d;
					}
					if( c == 2 ) {
						OS_EventFlag.1(bit) = 1;
						CurrentTone2 = (int)d;
					}
				}
			}
			
			last0 = d;
			
			index0 + 1;
			d = music_list0[index0];
			time0 = d;
			index0 + 1;
			break;
		}
		return is_play0;
	}
}




