xref: /MusicPlayer2/MusicPlayer2/SongInfo.h (revision 965ce478a79b0d21e8a6e2ade0490efa175855dd)
1 #pragma once
2 #include "Time.h"
3 
4 enum eTagType
5 {
6     T_OTHER_TAG = 0,
7     T_ID3V1 = 1,
8     T_ID3V2 = 1 << 1,
9     T_APE = 1 << 2,
10     T_RIFF = 1 << 3,
11     T_MP4 = 1 << 4,
12 };
13 
14 //排序方式
15 enum SortMode
16 {
17     SM_U_FILE = 0,          // 文件名 升序
18     SM_D_FILE,              // 文件名 降序
19     SM_U_PATH,              // 路径 升序
20     SM_D_PATH,              // 路径 降序
21     SM_U_TITLE,             // 标题 升序
22     SM_D_TITLE,             // 标题 降序
23     SM_U_ARTIST,            // 艺术家 升序
24     SM_D_ARTIST,            // 艺术家 降序
25     SM_U_ALBUM,             // 专辑 升序
26     SM_D_ALBUM,             // 专辑 降序
27     SM_U_TRACK,             // 音轨号 升序
28     SM_D_TRACK,             // 音轨号 降序
29     SM_U_LISTEN,            // 累计播放时间 升序
30     SM_D_LISTEN,            // 累计播放时间 降序
31     SM_U_TIME,              // 修改日期 升序
32     SM_D_TIME,              // 修改日期 降序
33     SM_U_GENRE,             // 流派 升序
34     SM_D_GENRE,             // 流派 降序
35     SM_U_YEAR,              // 年份 升序
36     SM_D_YEAR,              // 年份 降序
37     SM_U_BITRATE,           // 比特率 升序
38     SM_D_BITRATE,           // 比特率 降序
39 
40     SM_UNSORT = 100,        // 未排序(进入播放列表模式时总是设置为此排序方式,且不进行持久化)
41 };
42 
43 //一首歌曲的信息
44 struct SongInfo
45 {
46     wstring file_path{};                // 歌曲的路径
47     wstring lyric_file{};               // 匹配的歌词文件的路径
48     wstring title;                      // 标题
49     wstring artist;                     // 艺术家
50     wstring album;                      // 唱片集
51     wstring comment;                    // 注释
52     wstring genre;                      // 流派
53     wstring cue_file_path;              // cue文件的路径
54     wstring album_artist;               // 唱片集艺术家
55     unsigned __int64 song_id{};         // 歌曲对应的网易云音乐中的歌曲ID<仅在媒体库内使用>
56     __int64 last_played_time{};         // 上次播放的时间<仅在媒体库内使用>
57     unsigned __int64 modified_time{};   // 修改时间
58     int track{};                        // 音轨序号
59     int listen_time{};                  // 歌曲累计听的时间(单位为秒)<仅在媒体库内使用>
60     int freq{};                         // 采样频率
61     Time start_pos{};                   // 音频的起始位置
62     Time end_pos{};                     // 音频的结束位置
63     unsigned short year{};              // 年份
64     short bitrate{};                    // 比特率
65     WORD flags{};                       // 保存一些标志<仅在媒体库内使用>
66     BYTE tag_type{};                    // 标签的类型(0:其他;1:ID3v1;2:ID3v2;3:APE)
67     BYTE genre_idx{ 255 };              // 以字节表示的流派号
68     bool info_acquired{ false };        // 如果已经获取到了信息,则为ture (实际上已完全没有作用,可以被modified_time==0和ChannelInfoAcquired代替,考虑移除)
69     bool is_favourite{ false };         // 是否在我喜欢的音乐列表内<仅在播放列表内使用>
70     bool is_cue{ false };               // 如果曲目是cue分轨,则为true
71     BYTE rating{ 255 };                 // 歌曲分级<仅在媒体库内使用>
72     BYTE bits{};                        // 位深度
73     BYTE channels{};                    // 声道数
74     BYTE total_tracks{};                // 曲目总数
75     BYTE disc_num{};                    // CD序号
76     BYTE total_discs{};                 // CD总数
77 
78     // 如果为true,则不在线下载歌词<flags bit0>
79     bool NoOnlineLyric() const;
80     // 如果为true,则不在线下载歌词<flags bit0>
81     void SetNoOnlineLyric(bool val);
82     // 如果为true,则不在线下载专辑封面<flags bit1>
83     bool NoOnlineAlbumCover() const;
84     // 如果为true,则不在线下载专辑封面<flags bit1>
85     void SetNoOnlineAlbumCover(bool val);
86     // 如果为true,则总是使用外部封面<flags bit2>
87     bool AlwaysUseExternalAlbumCover() const;
88     // 如果为true,则总是使用外部封面<flags bit2>
89     void SetAlwaysUseExternalAlbumCover(bool val);
90     // 采样率、位深度、声道数信息是否已获取<flags bit3>
91     bool ChannelInfoAcquired() const;
92     // 采样率、位深度、声道数信息是否已获取<flags bit3>
93     void SetChannelInfoAcquired(bool val);
94 
95     //从另一个SongInfo对象复制标签信息
96     void CopyAudioTag(const SongInfo& song_info);
97 
98     bool IsTitleEmpty() const;
99     bool IsArtistEmpty() const;
100     bool IsAlbumEmpty() const;
101     bool IsYearEmpty() const;
102     bool IsGenreEmpty() const;
103 
104     // 获取艺术家列表(可能存在多个艺术家)
105     void GetArtistList(vector<wstring>& artist_list) const;
106     // TODO: 迁移所有用于文件名的艺术家字符串从这里获取
107     // 获取首个艺术家(作为文件名时请从这里获取以限制长度)
108     wstring GetFirstArtist() const;
109 
110     wstring GetTitle() const;
111     wstring GetArtist() const;
112     wstring GetAlbum() const;
113     wstring GetYear() const;
114     wstring get_year() const;
115     wstring GetGenre() const;
116     wstring GetFileName() const;
117     wstring GetSongId() const;
118 
119     void SetYear(const wchar_t* str_year);
120     void SetSongId(const wstring& id);
121 
122     bool IsEmpty() const;
123     Time length() const;
124     // 判断是否为相同歌曲,原比较代码有漏洞,请迁移所有比较到使用此方法
125     bool IsSameSong(const SongInfo& song) const;
126     // 清除歌曲信息中的<>内的默认字符串
127     void Normalize();
128 
129     // 获取SongInfo的排序谓词方法
130     static std::function<bool(const SongInfo& a, const SongInfo& b)> GetSortFunc(SortMode sort_mode);
131     // 获取排序方式的显示名称
132     static wstring GetSortModeDisplayName(SortMode sort_mode);
133 };
134 
135 struct SongKey
136 {
137     wstring path;
138     int cue_track{};    // 当存储cue时用来保存音轨号,其他情况为0
139 
SongKeySongKey140     SongKey() {}
SongKeySongKey141     SongKey(const wstring& path) : path(path)
142     {
143         ASSERT(!path.empty());
144     }
SongKeySongKey145     SongKey(const wstring& path, const int& cue_track) : path(path), cue_track(cue_track)
146     {
147         ASSERT(!path.empty());
148     }
SongKeySongKey149     SongKey(const SongInfo& song_info)
150     {
151         ASSERT(!song_info.file_path.empty());
152         path = song_info.file_path;
153         if (song_info.is_cue)
154             cue_track = song_info.track;
155     }
156     bool operator<(const SongKey& key) const
157     {
158         if (int pathComparison = path.compare(key.path))
159             return pathComparison < 0;
160         return cue_track < key.cue_track;
161     }
162     bool operator==(const SongInfo& other) const
163     {
164         if ((cue_track > 0) != other.is_cue)                // is_cue不同
165             return false;
166         if (path != other.file_path)                        // 路径不同
167             return false;
168         if ((cue_track > 0) && cue_track != other.track)    // is_cue为true时音轨号不同
169             return false;
170         return true;
171     }
172 };
173 
174 namespace std {
175     template <>
176     struct hash<SongKey> {
177         std::size_t operator()(const SongKey& key) const {
178             return std::hash<wstring>()(key.path) ^ std::hash<int>()(key.cue_track);
179         }
180     };
181     template <>
182     struct equal_to<SongKey> {
183         bool operator()(const SongKey& lhs, const SongKey& rhs) const {
184             return lhs.path == rhs.path && lhs.cue_track == rhs.cue_track;
185         }
186     };
187 }
188