📄 gwtspirit.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 + -