您的位置:首页 > 其它

歌词文件lrc的解析类(目前在WINCE下使用)

2010-04-29 10:06 423 查看
用到歌词显示就写了一个歌词解析类,与大家共同分享。

贴出头文件:

/********************************************************************
	created:	2009/10/30
	created:	30:10:2009   10:17
	filename: 	f:/工作_ZWF(090511)/TCC89X/PT4321/mylrcfile/BnvLrcHanderW.h
	file path:	f:/工作_ZWF(090511)/TCC89X/PT4321/mylrcfile
	file base:	BnvLrcHander
	file ext:	h
	author:		zhangwf
	
	purpose:	从原先代码中提取出歌词分析读取的类,使得结构更加清晰,便于
	            以后的修改与维护
	修改:       修改为支持UNICODE格式的
使用方法:  
1、设置歌词路径名SetFilePathName,或者设置音乐文件路径名(默认为歌词和歌曲同目录且名字相同)
2、根据当前播放时间值通过GetLyricLineItem接口获得当前需要显示的歌词项
3、如果还需要显示该行前的或后的行的歌词,则可以通过上述函数带出的索引值index,
   向前或向后通过GetLyricLineItem函数获取歌词项,来显示。
4、当然也可以通过GetLyricLineCounts获取所有歌词项,通过GetLyricLineItem获取每一项进行比较显示歌词。	        
*********************************************************************/
#ifndef _BNV_LRC_HANDER_W_H_
#define _BNV_LRC_HANDER_W_H_
//////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
//////////////////////////////////////////////////////////////////////////
// 定义歌词中的一项结构
typedef struct _LRC_ITEM_
{
	wstring Time;
	wstring Context;
}LRCITEM;
//////////////////////////////////////////////////////////////////////////
class BnvLrcHanderW
{
public: // 接口函数
	// 设置音乐文件路径名(默认为歌词与歌曲同名且在同一个路径下)
	BOOL SetMusicFilePathName(const wchar_t *filePathName);
	// 设置歌词文件路径名
	BOOL SetLrcFilePathName(const wchar_t *filePathName);	
	// 得到歌词行数
	int GetLyricLineCounts();
	// 得到具体行的歌词项,lineIndex从0开始(歌词已经按时间由小到大排列)
	BOOL GetLyricLineItem(LRCITEM &lineItem, int lineIndex);
	// 根据时间值得到歌词项(时间格式分钟、秒、毫秒)
	BOOL GetLyricLineItem(LRCITEM &lineItem, int *itemIndex, int minutes, int seconds=0, int millisecond=0);
	// playTime的格式必须为mm:ss.fff,也就是(分钟:秒.毫秒)
	BOOL GetLyricLineItem(LRCITEM &lineItem, int *itemIndex, wstring playTime);
	// 是否得到歌词信息
	BOOL GetLrcSuccess();
	// 得到歌曲的其他信息
	wstring GetArtist();
	wstring GetTitle();
	wstring GetAlbum();
	wstring GetByBody();
	int GetTimeOffset();  // 时间偏移值暂时没有使用
public:
	BnvLrcHanderW();
	~BnvLrcHanderW();
private: // 私有函数
	// 解析歌词文件
	BOOL PerseLrcFile(const wchar_t *filePathName);
	// 清空上次记录
	void ClearLrcInfo();
	// 操作列表的函数
	void AddToList(const LRCITEM &curLrcItem);
	void ClearList();
	int GetListSize();
	// 清除一项里的内容
	void ClearLrcItem(LRCITEM &curItem);
private:
	wstring m_strArtist;     // [ar:艺人名]
	wstring m_strTitle;      // [ti:曲名]
	wstring m_strAlbum;      // [al:专辑名]
	wstring m_strByBody;     // [by:编辑者]
	int    m_nOffset;       // [offset:时间补偿值]其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的
	// 定义存放解析到歌词的列表
	vector<LRCITEM> m_LyricList; 
	BOOL m_blHaveLrc;            // 记录是否加载到歌词文件
};
//////////////////////////////////////////////////////////////////////////
#endif






贴出源文件:

/********************************************************************
	created:	2009/10/30
	created:	30:10:2009   10:17
	filename: 	f:/工作_ZWF(090511)/TCC89X/PT4321/mylrcfile/BnvLrcHanderWW.cpp
	file path:	f:/工作_ZWF(090511)/TCC89X/PT4321/mylrcfile
	file base:	BnvLrcHanderW
	file ext:	cpp
	author:		zhangwf
	
	purpose:	从原先代码中提取出歌词分析读取的类,使得结构更加清晰,便于
	            以后的修改与维护
	修改:       修改为支持UNICODE格式的
*********************************************************************/
#include "BnvLrcHanderW.h"
#include <Windows.h>
//////////////////////////////////////////////////////////////////////////
bool MinFirstW(LRCITEM a, LRCITEM b) //比较大小
{   
	return a.Time < b.Time; 
}
//////////////////////////////////////////////////////////////////////////
BnvLrcHanderW::BnvLrcHanderW()
{
	// 初始化
	ClearLrcInfo();
}
BnvLrcHanderW::~BnvLrcHanderW()
{
	// 清除内容
	ClearLrcInfo();
}
//////////////////////////////////////////////////////////////////////////
BOOL BnvLrcHanderW::PerseLrcFile(const wchar_t *filePathName)
{
	// 清空上次数据
	ClearLrcInfo();
	// 参数有效性
	if (filePathName == NULL)
	{
		return FALSE;
	}
	// 打开歌词文件失败
	wfstream filestr;
	filestr.open(filePathName, ios_base::in);
	if (!filestr.is_open())
	{
		return FALSE;
	}
	// 分析歌词文件
	wstring lineData = L"";    // 读取一行的内容
	wstring itemContext = L""; // 该行的歌词内容
	wstring tagInfo = L"";     // 【】标签中的内容
	size_t preTag;           // 找到【的位置
	size_t endTag;           // 找到】的位置
	size_t pointPos;         // 找到:的位置
	LRCITEM lineItem;        // 得到该行的歌词信息
	while (!filestr.eof())
	{
		// 读取一行
		lineData = L"";
		getline(filestr, lineData);
		// 查找‘]’,一行标签中可以含有过个时间标签
		while (lineData.find(L"]") != wstring::npos)
		{
			// 从最后找"]",此后就是歌词内容了
			endTag = lineData.rfind(L"]", wstring::npos);
			itemContext = lineData.substr(endTag+1);
			// 从开始找"["和"]",确定标签中的信息
			preTag = lineData.find(L"[");
			endTag = lineData.find(L"]");
			tagInfo = lineData.substr(preTag+1, endTag-preTag-1);
			// 改变该行的值向后查找
			lineData = lineData.substr(endTag+1);
			// 分析标签内容
			if (tagInfo.find(L"al:") != wstring::npos)
			{
				pointPos = tagInfo.find(L":");
				m_strAlbum = tagInfo.substr(pointPos+1);
			}		
			else if(tagInfo.find(L"ar:") != wstring::npos)
			{
				pointPos = tagInfo.find(L":");
				m_strArtist = tagInfo.substr(pointPos+1);
			}
			else if(tagInfo.find(L"ti:") != wstring::npos)
			{
				pointPos = tagInfo.find(L":");
				m_strTitle = tagInfo.substr(pointPos+1);
			}
			else if (tagInfo.find(L"by:") != wstring::npos)
			{
				pointPos = tagInfo.find(L":");
				m_strByBody = tagInfo.substr(pointPos+1);
			}
			else if (tagInfo.find(L"offset:") != wstring::npos)
			{
				pointPos = tagInfo.find(L":");
				m_nOffset = _wtol(tagInfo.substr(pointPos+1).c_str());					
			}
			// 是时间标签,添加歌词到列表
			else
			{
				lineItem.Time = tagInfo;
				lineItem.Context = itemContext;
				AddToList(lineItem);
			}
		}
	}
	// 关闭文件并排序
	filestr.close();
	sort(m_LyricList.begin(), m_LyricList.end(), MinFirstW); 
	m_blHaveLrc = TRUE; // 加载到歌词
	return TRUE;
}
// 清空上次记录
void BnvLrcHanderW::ClearLrcInfo()
{
	m_blHaveLrc = FALSE;  // 没有歌词
	// 清空list内容
	ClearList();
	// 清空其他内容
	m_strArtist = L"";
	m_strTitle = L"";
	m_strByBody = L"";
	m_strAlbum = L"";
	m_nOffset = 0;	
}
// 添加一项到列表中
void BnvLrcHanderW::AddToList(const LRCITEM &curLrcItem)
{
	m_LyricList.push_back(curLrcItem);
}
// 清空列表内容
void BnvLrcHanderW::ClearList()
{
	m_LyricList.clear();		
	while (!m_LyricList.empty())
	{
		m_LyricList.pop_back();
	}
}
// 获得列表项的数量
int BnvLrcHanderW::GetListSize()
{
	return (int)m_LyricList.size();
}
// 清除一项里的内容
void BnvLrcHanderW::ClearLrcItem(LRCITEM &curItem)
{
	curItem.Time = L"";
	curItem.Context = L"";
}
//////////////////////////////////////////////////////////////////////////
// 接口函数
BOOL BnvLrcHanderW::SetLrcFilePathName(const wchar_t *filePathName)
{
	return PerseLrcFile(filePathName);
}
// 设置音乐文件路径名(默认为歌词与歌曲同名且在同一个路径下)
BOOL BnvLrcHanderW::SetMusicFilePathName(const wchar_t *filePathName)
{
	// 清除上次歌词
	ClearLrcInfo();
	// 参数有效性
	if (filePathName == NULL)
	{
		return FALSE;
	}	
	// 根据音乐文件名获取歌词文件名
	wchar_t lrcFilePathName[514];
	memset(lrcFilePathName, 0, sizeof(lrcFilePathName));
	wsprintf(lrcFilePathName, L"%s", filePathName);
	// 从后向前找‘.’的位置
	int pathLen = wcslen(lrcFilePathName);
	int dotPos = pathLen-1;
	while (dotPos >= 0)
	{
		if (lrcFilePathName[dotPos] == L'.')
		{
			break;
		}
		dotPos--;
	}
	// 没有找到.的位置
	if (dotPos < 0)
	{
		return FALSE;
	}
	// 路径太长
	if (dotPos+4 >= sizeof(lrcFilePathName))
	{
		return FALSE;
	}
	// '.'后的位置替换为.lrc
	lrcFilePathName[dotPos+1] = L'l';
	lrcFilePathName[dotPos+2] = L'r';
	lrcFilePathName[dotPos+3] = L'c';
	lrcFilePathName[dotPos+4] = L'/0';	
	// 解析歌词文件
	return PerseLrcFile(lrcFilePathName);	
}
// 得到歌词行数
int BnvLrcHanderW::GetLyricLineCounts()
{
	return GetListSize();
}
// 得到具体行的歌词项,lineIndex从0开始
BOOL BnvLrcHanderW::GetLyricLineItem(LRCITEM &lineItem, int lineIndex)
{
	// 参数有效性
	if (lineIndex<0 || lineIndex>=GetListSize())
	{
		return FALSE;
	}
	// 得到该项
	ClearLrcItem(lineItem);
	lineItem = m_LyricList.at(lineIndex);
	return TRUE;	
}
// 得到歌曲的其他信息
wstring BnvLrcHanderW::GetArtist()
{
	return m_strArtist;
}
wstring BnvLrcHanderW::GetTitle()
{
	return m_strTitle;
}
wstring BnvLrcHanderW::GetAlbum()
{
	return m_strAlbum;
}
wstring BnvLrcHanderW::GetByBody()
{
	return m_strByBody;
}
int BnvLrcHanderW::GetTimeOffset()
{
	return m_nOffset;
}
/********************************************************************
	函数名:GetLyricLineItem
	作者:zhangwf
	日期:2009/10/30
	功能:根据时间值得到歌词项(时间格式分钟、秒、毫秒)   
	参数:lineItem   带出歌词项(输出)
	      itemIndex   带出歌词项在列表中的索引(输出)
		  minutes     分钟数
		  seconds     秒数
		  millisecond   毫秒数
	返回:类型()
	修改记录:
*********************************************************************/
BOOL BnvLrcHanderW::GetLyricLineItem(LRCITEM &lineItem, int *itemIndex, int minutes, int seconds, int millisecond)
{
	// 参数有效性
	if (minutes<0 || seconds<0 || millisecond<0)
	{
		return FALSE;
	}
	// 清除内容
	ClearLrcItem(lineItem);
	// 得到当前时间字符串
	wchar_t curTime[32];
	wsprintf(curTime, L"%02d:%02d.%03d", minutes, seconds, millisecond);	
	wstring playTime(L"");
	playTime.append(curTime);
	// 取得歌词行数
	int itemCounts = GetListSize();
	if (itemCounts <= 0)
	{
		return FALSE;
	}
	// 在除去最后一项中遍历找出当前符合条件的歌词	
	for (int index=0; index<itemCounts-1; index++)
	{		
		if (m_LyricList.at(index).Time<=playTime && playTime<m_LyricList.at(index+1).Time)
		{		
			lineItem = m_LyricList.at(index);
			if (itemIndex != NULL)
			{
				*itemIndex = index;
			}
			return TRUE;
		}
	}
	// 没有找到,看最后一项是否要找的歌词
	if (m_LyricList.at(itemCounts-1).Time <= playTime)
	{		
		lineItem = m_LyricList.at(itemCounts-1);
		if (itemIndex != NULL)
		{
			*itemIndex = itemCounts-1;
		}
		return TRUE;
	}
	// 没有找到合适的
	return FALSE;	
}
/********************************************************************
	函数名:GetLyricLineItem
	作者:zhangwf
	日期:2009/10/30
	功能:根据时间获得当前播放的歌词项       
	参数:lineItem   带出歌词项(输出)
		  itemIndex   带出歌词项在列表中的索引(输出)
		  playTime的格式必须为mm:ss.fff,也就是(分钟:秒.毫秒)
	返回:类型()
	修改记录:
*********************************************************************/
BOOL BnvLrcHanderW::GetLyricLineItem(LRCITEM &lineItem, int *itemIndex, wstring playTime)
{
	// 清除内容
	ClearLrcItem(lineItem);
	// 取得歌词行总数
	int itemCounts = GetListSize();
	if (itemCounts <= 0)
	{
		return FALSE;
	}
	// 在除去最后一项中遍历找出当前符合条件的歌词
	for (int index=0; index<itemCounts-1; index++)
	{
		if (m_LyricList.at(index).Time<=playTime && playTime<m_LyricList.at(index+1).Time)
		{			
			lineItem = m_LyricList.at(index);
			if (itemIndex != NULL)
			{
				*itemIndex = index;
			}
			return TRUE;
		}
	}
	// 没有找到,看最后一项是否要找的歌词
	if (m_LyricList.at(itemCounts-1).Time <= playTime)
	{		
		lineItem = m_LyricList.at(itemCounts-1);
		if (itemIndex != NULL)
		{
			*itemIndex = itemCounts-1;
		}
		return TRUE;
	}
	// 没有找到合适的
	return FALSE;
}
/********************************************************************
	函数名:GetLrcSuccess
	作者:zhangwf
	日期:2009/11/02
	功能:是否得到歌词信息,在音乐播放界面需要判断是否有歌词信息,否则显示ID3信息       
	参数:
	返回:类型()
	修改记录:
*********************************************************************/
BOOL BnvLrcHanderW::GetLrcSuccess()
{
	return m_blHaveLrc;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: