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

📄 gwtspirit.h

📁 MP4源代码
💻 H
字号:
#include "mmsystem.h"
#pragma comment(lib, "WINMM.LIB")
#include "iostream"
#include "fstream"
#include "string"
using namespace std;

class GBUTTON
{
public:
	PIMAGE imgNormal,imgSkim,imgClick;
	int imgX,imgY,imgW,imgH;
	int state;//0不显示按钮 1显示imgNormal 2imgSkim 3imgClick
	int keyMsgRender;//用于编程者设置何种鼠标消息响应imgClick显示,默认WM_LBUTTONDOWN

	int MidPos(int destL,int srcL)
	{return (destL-srcL)/2;}
	ChangePrivateId(int id)
	{myId=id;}
	SetText(LPCSTR title,PIMAGE dest,COLORREF bkColor,COLORREF wordColor)
	{
		int WordX=MidPos(imgW,textwidth(title));
		int WordY=MidPos(imgH,textheight(title));
		setbkcolor(bkColor,dest);
		setcolor(wordColor,dest);
		cleardevice(dest);
		outtextxy(WordX,WordY,title,dest);
	}
	SetDefText(LPCSTR title)
	{
		SetText(title,imgNormal,0xca7788,WHITE);
		SetText(title,imgSkim,YELLOW,LIGHTMAGENTA);
		SetText(title,imgClick,0x2244ff,WHITE);
	}

	//Initialize
	GBUTTON(LPCSTR title,int buttonId,int posX,int posY,int wid,int hgt,int style=0,int keymsgrender=WM_LBUTTONDOWN)//style值:0默认普通文字提示按钮(用户仍可调用后继续自己绘制) 其他值则需要用户自己绘制三种img:自由绘制或调用本class专用函数绘制
	{
		myId=buttonId;
		keyMsgRender=keymsgrender;
		state=1;
		imgNormal=new IMAGE(wid,hgt);
		imgSkim  =new IMAGE(wid,hgt);
		imgClick =new IMAGE(wid,hgt);
		imgX	 =posX;
		imgY	 =posY;
		imgW	 =wid;
		imgH	 =hgt;		
		if(!style)
			SetDefText(title);
	}
	Update(MOUSEMSG *mouse,int *buttonId)//这种传入方法允许编程时只需外部定义一个鼠标事件结构体
	{
		int x,y;
		GetMousePos(&x,&y);
		if(BeCrashed(x,y,1,1,imgX,imgY,imgW,imgH))
		{
			(*mouse)=GetMouseMsg();
			state=2;
			if(mouse->uMsg==keyMsgRender)
			{
				state=3;
				*buttonId=myId;
			}
		}
		else
		{
			state=1;
		}
	}
	Render(PIMAGE dest=NULL,int switchblend=0,unsigned char alpha=100)//switchblend半透明开关 alpha透明度(范围0-0xff)
	{
		if((!dest))
		{
			if(state==1)
			{	
				if(switchblend)	putimage_alphablend(dest,imgNormal,imgX,imgY,alpha);
				else			putimage(imgX,imgY,imgNormal);
			}
			if(state==2)putimage(imgX,imgY,imgSkim);
			if(state==3)putimage(imgX,imgY,imgClick);	
		}
		else
		{
			if(state==1)
			{
				if(switchblend)	putimage_alphablend(dest,imgNormal,imgX,imgY,alpha);
				else			putimage(dest,imgX,imgY,imgNormal);
			}

			if(state==2)putimage(dest,imgX,imgY,imgSkim);
			if(state==3)putimage(dest,imgX,imgY,imgClick);
		}
	}
	~GBUTTON(){delete imgNormal,imgClick,imgSkim;}

protected:
private:
	int myId;
};

class MUSIC
{
public:
	Init(char fpath[])
	{
		//赋值shortpath
		sprintf(filepath,"%s",fpath);
		GetShortPathName(filepath,shortpath,sizeof(shortpath));
	}
	int GetState()//0停止 1播放 2暂停
	{
		char state[50];
		wsprintf(cmd,"status %s mode",shortpath);//创建一条命令	
		if(err=mciSendString (cmd,state, sizeof(state)/sizeof(TCHAR), 0))//检查正在播放的状态)
		{
			sprintf(cmd,"getstate errid:%d",err);
			cout<<cmd<<endl;
		}
		if(strcmp(state,"stopped")==0)	return 0;
		else if(strcmp(state,"playing")==0)return 1;
		else if(strcmp(state,"paused")==0)	return 2;
		else 
			return 99;
	}
	int GetVoice()
	{
		char volume[50];
		sprintf(cmd,"status %s volume",shortpath);
		if(err=mciSendString(cmd,volume, 255, 0 ))
		{
			sprintf(volume,"getvoice err id:%d",err);
			cout<<volume<<endl;
		}
		else
			return atoi(volume);//把字符串类型转为Int型,要include<stdlib.h>
		return 0;
	}
	LPCSTR GetFileName(int mode=1)//1 全名 2 短名
	{
		if(mode==1)return filepath;
		return shortpath;
	}
	//歌曲控制
	SetVoice(int newVoice)
	{
		sprintf(cmd,"setaudio %s volume to %d",shortpath,newVoice);//修改音量
		if(err=mciSendString(cmd,NULL,0,NULL))
		{
			sprintf(cmd,"setvoice err id:%d",err);
			cout<<cmd<<endl;
		}
	}

	Stop()
	{
		cout<<"stop "<<shortpath<<endl;
		sprintf(cmd,"stop %s",shortpath);
		mciSendString(cmd,NULL,0,NULL);
		sprintf(cmd,"close %s",shortpath);
		mciSendString(cmd,NULL,0,NULL);//释放资源
	}

	Pause()
	{
		cout<<"pause "<<shortpath<<endl;
		sprintf(cmd,"pause %s",shortpath);
		if(err=mciSendString(cmd,NULL,0,NULL))
		{
			sprintf(cmd,"pause err id:%d",err);
			cout<<cmd<<endl;
		}
	}
	Play()
	{
		cout<<"play "<<shortpath<<endl;
		sprintf(cmd,"play %s",shortpath);
		if(err=mciSendString(cmd,NULL,0,NULL))
		{
			sprintf(cmd,"1play err id:%d",err);
			cout<<cmd<<endl;
		}
	}
protected:
private:
	char filepath[MAX_PATH],shortpath[MAX_PATH];
	int voice;
	int err;
	char cmd[MAX_PATH];
};
struct MP3Msg
{
	char taget[4],Title[31],Artist[31],Album[31],Year[5],Comment[31],Reserved[2];
};
class MP3INFO
{
private:
	MP3Msg *aMp3Msg;
	char fpath[MAX_PATH];
	FILE *fp;
	string strbuf;
	int num;
public:
	~MP3INFO()
	{delete aMp3Msg;strbuf.~string();}
	int Init(LPCTSTR filepath)//true正常 false open err
	{	
		sprintf(fpath,"%s",filepath);

		aMp3Msg=(MP3Msg*)malloc(sizeof(MP3Msg));
		ZeroMemory(aMp3Msg,sizeof(MP3Msg));

		if(fp=fopen(fpath,"rb"));
		else{fclose(fp);return false;}

		fseek(fp,-128L,2);
		fgets(aMp3Msg->taget,4,fp);
		fseek(fp,-125L,2);
		fgets(aMp3Msg->Title,31,fp);
		fseek(fp,-95L,2);
		fgets(aMp3Msg->Artist,31,fp);
		fseek(fp,-65L,2);
		fgets(aMp3Msg->Album,31,fp);
		fseek(fp,-35L,2);
		fgets(aMp3Msg->Year,5,fp);
		fseek(fp,-31L,2);
		fgets(aMp3Msg->Comment,31,fp);
		fclose(fp);
		return true;
	}
	LPCSTR		GetTitle()		{return aMp3Msg->Title;}
	LPCSTR		GetArtist()		{return aMp3Msg->Artist;}
	LPCSTR		GetAlbum()		{return aMp3Msg->Album;}
	LPCSTR		GetYear()		{return aMp3Msg->Year;}
	LPCSTR		GetComment()	{return aMp3Msg->Comment;}
	LPCSTR		GetFPath()		{return fpath;}
	bool OpenToSetVal()//凡调用本类的前缀set-的函数(下方),必须至少首先调用1次,再调用CloseToSetVal();
	{
		if(fp=fopen(fpath,"rb+"))return true;
		else{fclose(fp);return false;}
	}
	SetTitle(string title)//本来想用LPCSTR的但是觉得既然常用string何必麻烦
	{
		num=title.size();
		if(num>30)
			title.resize(30,'\0');
		else if(num>0)
		{
			fseek(fp,-125L,2);
			fputs(title.c_str(),fp);
			for(int i=0;i<30-num;++i)
				fputc(0,fp);
		}
	}
	SetArtist(string title)//本来想用LPCSTR的但是觉得既然常用string何必麻烦
	{
		num=title.size();
		if(num>30)
			title.resize(30,'\0');
		else if(num>0)
		{
			fseek(fp,-95L,2);
			fputs(title.c_str(),fp);
			for(int i=0;i<30-num;++i)
				fputc(0,fp);
		}
	}
	SetAlbum(string title)//本来想用LPCSTR的但是觉得既然常用string何必麻烦
	{
		num=title.size();
		if(num>30)
			title.resize(30,'\0');
		else if(num>0)
		{
			fseek(fp,-65L,2);
			fputs(title.c_str(),fp);
			for(int i=0;i<30-num;++i)
				fputc(0,fp);
		}
	}
	SetYear(string title)//本来想用LPCSTR的但是觉得既然常用string何必麻烦
	{
		num=title.size();
		if(num>4)
			title.resize(4,'\0');
		else if(num>0)
		{
			fseek(fp,-35L,2);
			fputs(title.c_str(),fp);
			for(int i=0;i<4-num;++i)
				fputc(0,fp);
		}
	}
	SetComment(string title)//本来想用LPCSTR的但是觉得既然常用string何必麻烦
	{
		num=title.size();
		if(num>30)
			title.resize(30,'\0');
		else if(num>0)
		{
			fseek(fp,-31L,2);
			fputs(title.c_str(),fp);
			for(int i=0;i<30-num;++i)
				fputc(0,fp);
		}
	}
	CloseToSetVal()
	{fclose(fp);}
};

class ALRC
{
public:
	int id;
	DWORD mm,ss,ff;//为达成精准时间设置为DWORD类型
	string lrcstr;
	
	Init(int nid,string nlrcstr,unsigned int nmm,unsigned int nss,unsigned int nff=0){id=nid,lrcstr=nlrcstr;mm=nmm,ss=nss,ff=nff;}
	
	bool StrEmpty(){return lrcstr.empty();}
	
	~ALRC(){lrcstr.~string();}
};

class LRCPLAYER
{
private:
	DWORD lrctime,lrcFirstTime,pauseDelayTime,pauseStartTime;
	string ar,ti,al,by,offset,lrcfile;
	unsigned int lrcnum,lrcid,state;
	ALRC lrc[0xff];

	string timeReturnString;

	bool CheckHaveLable(string str){if(str.find(']')!=-1)return true;return false;}
	string GetLastString(string str)//这句有很大问题:1如果]符号为非脚本内的呢2若为非法脚本,返回的npos值该做何工作呢
	{return str.substr(str.find_last_of(']')+1);}
	string GetFLable(string str)//返回第一个诸如ar:author类的lable
	{
		int p1=str.find('['),p2=str.find(':'),p3=str.find(']');
		if(p1<p2&&p2<p3)//该句含合法标签
		{
			str.erase(p1,1);
			str.erase(p3-1);
		}
		return str;
	}
	string DeleteFLable(string str)//去掉第一个lable的字符串
	{return str.substr(str.find(']')+1);}
	string GetLableF(string lab,char c)//返回lable:前的字符串
	{return lab.substr(0,lab.find(c));}//substr:截取字符串
	string GetLableL(string lab,char c)//返回lable:后的字符串
	{return lab.substr(lab.find(c)+1);}//substr:截取字符串

	DWORD GetVSumTime(ALRC a)//内部:获取非标准时间和,仅用于比较
	{return a.mm*60000+a.ss*1000+a.ff;}
	LrcSwap(char id1,char id2)
	{
		ALRC buf;
		buf.Init(id1,lrc[id1].lrcstr,lrc[id1].mm,lrc[id1].ss,lrc[id1].ff);
		lrc[id1].Init(id2,lrc[id2].lrcstr,lrc[id2].mm,lrc[id2].ss,lrc[id2].ff);
		lrc[id2].Init(buf.id,buf.lrcstr,buf.mm,buf.ss,buf.ff);
	}
	LrcTimeSortOrder()
	{for(int i=lrcnum;i>0;i--)for(int j=0;j<i;j++)
			if( GetVSumTime(lrc[j])>GetVSumTime(lrc[j+1]) )//小数放前大数放后
				LrcSwap(j,j+1);//交换
	}
	
public:
	~LRCPLAYER(){ar.~string(),ti.~string(),al.~string(),by.~string(),offset.~string(),lrcfile.~string(),timeReturnString.~string();}
	bool InitLrc(string mp3file)//歌词初始化,初始播放歌曲时调用此函数。输入:MP3文件路径 返回值0无此歌词,1有歌词
	{
		lrcfile=mp3file;
		mp3file=lrcfile.substr(0,lrcfile.find('.'));
		lrcid=0;
		lrcfile=mp3file+".lrc";

		ifstream in(lrcfile.c_str());
		if(in.fail())
		{
			lrcnum=0;
			return false;
		}
		else
		{
			
			for(int i=0;i<0xff;i++)
				lrc[i].lrcstr=" ";
			string sbuf0,sbuf1,sbuf2,sbuf3;
			unsigned int mm,ss,ff;
			string lrcstr;
			while(getline(in,sbuf0))
			{
				while(CheckHaveLable(sbuf0))
				{
					lrcstr=GetLastString(sbuf0);
					string lab=GetFLable(sbuf0);
					sbuf0=DeleteFLable(sbuf0);
					sbuf1=GetLableF(lab,':');
					sbuf2=GetLableL(lab,':');
					if(sbuf1=="ar")ar=sbuf2;
					else if(sbuf1=="ti")ti=sbuf2;
					else if(sbuf1=="al")al=sbuf2;
					else if(sbuf1=="by")by=sbuf2;
					else if(sbuf1=="offset")offset=sbuf2;
					else
					{
						mm=atoi(sbuf1.c_str()); 
						if(sbuf2.find('.')==-1)//易错A
						{
							ss=atoi(sbuf2.c_str());//尚不支持.ff
							ff=0;
						}
						else//若有.ff文件的操作方法
						{
							
							sbuf1=GetLableF(sbuf2,'.');
							ss=atoi(sbuf1.c_str());
							sbuf1=GetLableL(sbuf2,'.');
							ff=atoi(sbuf1.c_str());
						}

						lrc[lrcid].Init(lrcid,lrcstr,mm,ss,ff);
						lrcid++;
						if(lrcid>0xff)lrcid=0xff;//不允许超过255句
					}
				}
			}
			LrcTimeSortOrder();
			sbuf0.~string(),sbuf1.~string(),sbuf2.~string(),sbuf3.~string(),lrcstr.~string();
		}
		in.close();
		lrcnum=lrcid-1;//可能是个bug,解决方法lrcid-1
		lrcid=0;//必须初始化,使得LrcTimeRetrunString()可用
		pauseStartTime=lrcFirstTime=timeGetTime();
		pauseDelayTime=0;
		state=1;//正常播放 0为音乐暂停
		return true;
	}

	LrcPause()//歌曲暂停时请调用该函数(提示:前提有LRC文件)
	{
		state=0;
		pauseStartTime=timeGetTime();
	}
	LrcContinue()//歌曲不再暂停,又开始继续播放时调用该函数(提示:前提有LRC文件)
	{
		state=1;
		pauseDelayTime=pauseDelayTime+timeGetTime()-pauseStartTime;
	}
	string LrcTimeReturnString()//播放时随时调用该函数则可获取当前LRC文件内的准时歌词
	{
		if(state==1)
		{
			DWORD dt=timeGetTime()-pauseDelayTime-lrcFirstTime;
			if(dt>=GetVSumTime(lrc[lrcid]))
			{
				timeReturnString=lrc[lrcid].lrcstr;
				if(lrcid<lrcnum)++lrcid;
			}
		}
		return timeReturnString;
	}
	string GetString(int id)//获取指定ID的歌词
	{return lrc[id].lrcstr;}

	int GetNowLrcId()//获取当前Lrc歌词显示的ID
	{return lrcid;}
	int GetLrcSum()//获取LRC歌词数量
	{return lrcnum;}
	LrcStrTest()//LRC测试:控制台窗口下显示扫描的歌词文件
	{
		for(int i=0;lrc[i].StrEmpty()==false;i++)
		{
			cout<<lrc[i].mm<<" : "<<lrc[i].ss<<" : "<<lrc[i].ff<<endl;
			cout<<i<<" "<<lrc[i].lrcstr<<endl<<endl;
		}	
	}
};

⌨️ 快捷键说明

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