xref: /MusicPlayer2/MusicPlayer2/Player.cpp (revision 9cffa0df29e4d7309e6a99c32ae9bd86c2ad1b1e)
1 #include "stdafx.h"
2 #include "Player.h"
3 #include "MusicPlayer2.h"
4 #include "COSUPlayerHelper.h"
5 #include "Playlist.h"
6 #include "BassCore.h"
7 #include "MciCore.h"
8 #include "FfmpegCore.h"
9 #include "MusicPlayerCmdHelper.h"
10 #include "SongDataManager.h"
11 #include "SongInfoHelper.h"
12 #include <random>
13 #include "IniHelper.h"
14 #include "CRecentList.h"
15 
16 CPlayer CPlayer::m_instance;
17 
CPlayer()18 CPlayer::CPlayer()
19 {
20 }
21 
GetInstance()22 CPlayer& CPlayer::GetInstance()
23 {
24     return m_instance;
25 }
26 
~CPlayer()27 CPlayer::~CPlayer()
28 {
29     UnInitPlayerCore();
30 }
31 
GetNextShuffleIdx() const32 inline int CPlayer::GetNextShuffleIdx() const {
33     // 获得下一m_shuffle_index
34     int next = m_shuffle_index + 1;
35     if (next >= static_cast<int>(m_shuffle_list.size()))
36         next = 0;
37     return next < 0 ? 0 : next;
38 }
39 
GetPrevShuffleIdx() const40 inline int CPlayer::GetPrevShuffleIdx() const {
41     // 获得前一m_shuffle_index
42     int prev = m_shuffle_index - 1;
43     if (prev < 0)
44         prev = static_cast<int>(m_shuffle_list.size()) - 1;
45     return prev < 0 ? 0 : prev;
46 }
47 
OnPlaylistChange()48 inline void CPlayer::OnPlaylistChange() {
49     //播放列表有修改时的相关操作,如清空下一首和随机播放记录
50     m_random_list.clear();
51     m_next_tracks.clear();
52     m_shuffle_list.clear();
53     m_is_shuffle_list_played = false;
54 }
55 
IniPlayerCore()56 void CPlayer::IniPlayerCore()
57 {
58     if (m_pCore == nullptr)
59     {
60         if (theApp.m_play_setting_data.use_mci)
61             m_pCore = new CMciCore();
62         else if (theApp.m_play_setting_data.use_ffmpeg)
63             m_pCore = new CFfmpegCore();
64 
65         //判断MCI或FFMPEG内核是否加载成功
66         CDllLib* dll_lib = dynamic_cast<CDllLib*>(m_pCore);
67         if (dll_lib != nullptr)
68         {
69             if (!dll_lib->IsSucceed())
70             {
71                 dll_lib->UnInit();
72                 delete m_pCore;
73                 m_pCore = nullptr;
74             }
75         }
76 
77         if (m_pCore == nullptr)
78         {
79             m_pCore = new CBassCore();
80             theApp.m_play_setting_data.use_mci = false;
81             theApp.m_play_setting_data.use_ffmpeg = false;
82         }
83 
84         m_pCore->InitCore();
85         m_player_core_inited = true;
86     }
87 }
88 
UnInitPlayerCore()89 void CPlayer::UnInitPlayerCore()
90 {
91     if (m_pCore != nullptr)
92     {
93         m_player_core_inited = false;
94         m_pCore->UnInitCore();
95         delete m_pCore;
96         m_pCore = nullptr;
97     }
98 }
99 
Create()100 void CPlayer::Create()
101 {
102     AfterSetTrack();     // 预先设置一次标题
103     IniPlayerCore();
104     LoadConfig();
105     m_controls.InitSMTC(theApp.m_play_setting_data.use_media_trans_control);
106 
107     ListItem cur_list = CRecentList::Instance().GetCurrentList();
108     // 如果文件夹模式且当前文件夹没有音频文件那么切换到默认播放列表
109     // 清理无效(空)文件夹会在启动时更新媒体库进行(如果启用remove_file_not_exist_when_update)
110     if (cur_list.type == LT_FOLDER && (cur_list.path.empty() || !CAudioCommon::IsPathContainsAudioFile(cur_list.path, cur_list.contain_sub_folder)))
111     {
112         cur_list = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_DEFAULT);
113     }
114     SetList(cur_list);
115 }
116 
CreateWithFiles(const vector<wstring> & files)117 void CPlayer::CreateWithFiles(const vector<wstring>& files)
118 {
119     AfterSetTrack();
120     IniPlayerCore();
121     LoadConfig();
122     m_controls.InitSMTC(theApp.m_play_setting_data.use_media_trans_control);
123     OpenFilesInDefaultPlaylist(files);
124 }
125 
CreateWithPath(const wstring & path)126 void CPlayer::CreateWithPath(const wstring& path)
127 {
128     AfterSetTrack();
129     IniPlayerCore();
130     LoadConfig();
131     m_controls.InitSMTC(theApp.m_play_setting_data.use_media_trans_control);
132     OpenFolder(path);
133 }
134 
CreateWithPlaylist(const wstring & playlist_path)135 void CPlayer::CreateWithPlaylist(const wstring& playlist_path)
136 {
137     AfterSetTrack();
138     IniPlayerCore();
139     LoadConfig();
140     m_controls.InitSMTC(theApp.m_play_setting_data.use_media_trans_control);
141     wstring playlist_path_{ playlist_path };
142     OpenPlaylistFile(playlist_path_);
143 }
144 
IniPlayList(bool play,MediaLibRefreshMode refresh_mode,SongKey song_key)145 void CPlayer::IniPlayList(bool play, MediaLibRefreshMode refresh_mode, SongKey song_key)
146 {
147     m_no_use = SongInfo{};  // 安全起见,防止意外写入被应用
148     m_playlist.clear();
149     //播放列表模式下
150     if (m_playlist_mode == PM_PLAYLIST)
151     {
152         CPlaylistFile playlist;
153         playlist.LoadFromFile(m_playlist_path);
154         playlist.MoveToSongList(m_playlist);
155     }
156     //媒体库播放列表模式下
157     else if (m_playlist_mode == PM_MEDIA_LIB)
158     {
159         // 根据类型和名称获取音频文件列表
160         if (m_media_lib_playlist_type == CMediaClassifier::CT_NONE)
161         {
162             //返回所有曲目
163             CSongDataManager::GetInstance().GetSongData([&](const CSongDataManager::SongDataMap& song_data_map)
164                 {
165                     for (const auto& song_info : song_data_map)
166                     {
167                         m_playlist.push_back(song_info.second);
168                     }
169                 });
170         }
171         else
172         {
173             CMediaClassifier classifier(m_media_lib_playlist_type, m_media_lib_playlist_name == STR_OTHER_CLASSIFY_TYPE);
174             classifier.ClassifyMedia();
175             m_playlist = classifier.GetMeidaList()[m_media_lib_playlist_name];
176         }
177     }
178     else
179     {
180         if (m_path.empty() || (m_path.back() != L'/' && m_path.back() != L'\\'))        //如果输入的新路径为空或末尾没有斜杠,则在末尾加上一个
181             m_path.append(1, L'\\');
182         CAudioCommon::GetAudioFiles(m_path, m_playlist, MAX_SONG_NUM, m_contain_sub_folder);
183     }
184     // 把ListItem的SongKey传递到这里是不能正常转换为play_index的,在cue下不能正常工作
185     // 临时这样用,等到CPlayer大改时这部分会重做
186     if (!song_key.path.empty())
187     {
188         auto iter = std::find_if(m_playlist.begin(), m_playlist.end(), [&](const SongInfo& item) { return song_key == item; });
189         if (iter != m_playlist.end())
190             m_thread_info.play_index = iter - m_playlist.begin();
191         else
192             m_thread_info.play_index = 0;
193     }
194     else
195         m_thread_info.play_index = m_index;
196 
197     m_thread_info.refresh_mode = refresh_mode;
198     m_thread_info.play = play;
199     m_thread_info.playlist_mode = m_playlist_mode;
200 
201     m_index = 0;            // 在初始化期间为维持程序其他部分不报错(可能需要(但不应该需要))保持m_playlist[m_index]有效
202     if (m_playlist.empty())
203         m_playlist.push_back(SongInfo{});       // 没有歌曲时向播放列表插入一个空的SongInfo对象
204 
205     //创建初始化播放列表的工作线程
206     m_pThread = AfxBeginThread(IniPlaylistThreadFunc, &m_thread_info);
207 }
208 
IniPlaylistThreadFunc(LPVOID lpParam)209 UINT CPlayer::IniPlaylistThreadFunc(LPVOID lpParam)
210 {
211     CCommon::SetThreadLanguageList(theApp.m_str_table.GetLanguageTag());
212     ThreadInfo* pInfo = (ThreadInfo*)lpParam;
213     wstring remove_list_path{ pInfo->remove_list_path };
214     ListItem remove_list{};
215     if (CCommon::IsFolder(pInfo->remove_list_path))
216         remove_list.type = LT_FOLDER;
217     else
218         remove_list.type = LT_PLAYLIST;
219     remove_list.path = pInfo->remove_list_path;
220     SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_PLAYLIST_INI_START, remove_list.path.empty() ? 0 : (WPARAM)&remove_list_path, 0);
221 
222     // 播放列表模式下且play_index有效时重新查找play_index指向曲目,文件夹模式下play_index本就描述初始化完成的播放列表故无须改动
223     SongInfo cur_song;
224     vector<SongInfo>& play_list = GetInstance().m_playlist;
225     if (pInfo->playlist_mode && pInfo->play_index >= 0 && pInfo->play_index < static_cast<int>(play_list.size()))
226         cur_song = play_list[pInfo->play_index];
227 
228     bool exit_flag{};
229     int update_cnt{};
230     if (!play_list.empty() && !play_list.front().IsEmpty())
231     {
232         // 解析cue并更新所有曲目到媒体库,执行后仅file_path、track、is_cue可用
233         // 此处不应设置ignore_short为true,因为现在正在初始化播放列表,如果读取到短文件却不保存有可能导致列表每次打开耗时都很长
234         CAudioCommon::GetAudioInfo(play_list, update_cnt, exit_flag, pInfo->process_percent, pInfo->refresh_mode);
235         // 将媒体库内信息更新到播放列表
236         CSongDataManager::GetInstance().LoadSongsInfo(play_list);
237     }
238 
239     bool find_succeed{ cur_song.file_path.empty() };    // 为true说明不必继续查找cur_song
240     // 重新查找当前播放
241     if (!find_succeed)
242     {
243         for (auto iter = play_list.begin(); iter != play_list.end(); ++iter)
244         {
245             if (cur_song.IsSameSong(*iter))
246             {
247                 pInfo->play_index = iter - play_list.begin();
248                 find_succeed = true;
249                 break;
250             }
251         }
252     }
253     // 如果没有找到那么说明受到了cue解析影响,有以下情况
254     if (!find_succeed && cur_song.is_cue)
255     {
256         // cue解析前就是cue条目时上面IsSameSong搜索失败的可能性很低,只有cue编辑等偏门条件能触发
257         // 这里按cue_file_path和track匹配查找
258         for (auto iter = play_list.begin(); iter != play_list.end(); ++iter)
259         {
260             if (!iter->is_cue) continue;
261             if (cur_song.track == iter->track && cur_song.cue_file_path == iter->cue_file_path)
262             {
263                 pInfo->play_index = iter - play_list.begin();
264                 find_succeed = true;
265                 break;
266             }
267         }
268         // 没有找到的话下面实质上是将此cue条目退化为“已被cue使用的原始音频”进行搜索
269     }
270     // cur_song是cue原始文件/已被cue使用的原始音频/含内嵌cue的原始音频,播放其(FILE标签中的)第一条音轨
271     if (!find_succeed)
272     {
273         int track{ INT_MAX };
274         const wstring& find_str = cur_song.file_path;
275         for (auto iter = play_list.begin(); iter != play_list.end(); ++iter)
276         {
277             if (!iter->is_cue) continue;    // 先判断开销较小的条件
278             if (iter->track > track) continue;
279             if (find_str == iter->cue_file_path || find_str == iter->file_path)
280             {
281                 track = iter->track;
282                 pInfo->play_index = iter - play_list.begin();
283                 find_succeed = true;
284                 if (track <= 1)     // cue不存在比1小的音轨号所以不必继续搜索
285                     break;
286             }
287         }
288     }
289 
290     PostMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_PLAYLIST_INI_COMPLATE, 0, 0);
291     return 0;
292 }
293 
IniPlaylistComplate()294 void CPlayer::IniPlaylistComplate()
295 {
296     m_index = m_thread_info.play_index;
297 
298     if (m_index < 0 || m_index >= GetSongNum())
299     {
300         m_index = 0;                    // 确保当前歌曲序号不会超过歌曲总数
301         m_current_position.fromInt(0);  // m_index失效时同时清除进度(这样略有不足,理论上只要m_index指向的歌曲改变就应当清除进度,不过这需要PathInfo和PlaylistInfo改track为SongInfo(SongKey))
302     }
303     //统计列表总时长
304     m_total_time = 0;
305     for (const auto& song : m_playlist)
306     {
307         m_total_time += song.length().toInt();
308     }
309 
310     //检查列表中的曲目是否在“我喜欢”播放列表中
311     CPlaylistFile favourite_playlist;
312     favourite_playlist.LoadFromFile(CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE).path);
313     for (auto& item : m_playlist)
314     {
315         item.is_favourite = favourite_playlist.IsSongInPlaylist(item);
316     }
317 
318     ASSERT(m_playing == 0);
319     // 对播放列表排序
320     if (m_playlist_mode == PM_PLAYLIST)                // 播放列表模式默认状态必须为未排序
321     {
322         ASSERT(m_sort_mode == SM_UNSORT);
323         m_sort_mode = SM_UNSORT;
324     }
325     else if (m_playlist_mode == PM_FOLDER && m_sort_mode == SM_UNSORT)  // 文件夹模式不允许为未排序
326     {
327         ASSERT(FALSE);
328         m_sort_mode = SM_U_FILE;
329     }
330     if ((m_playlist_mode == PM_FOLDER || m_playlist_mode == PM_MEDIA_LIB) && m_playlist.size() > 1)
331         SortPlaylist(true);
332 
333     if (!IsPlaylistEmpty())         // 播放列表初始化完成,根据m_index,m_current_position,m_thread_info.play还原播放状态
334     {
335         bool tmp_find{ false };
336         if (!m_current_song_tmp.IsEmpty())     // m_current_song_tmp不为空则改为查找播放此歌曲,同时定位到m_current_song_position_tmp
337         {
338             for (size_t i{}; i < m_playlist.size(); i++)
339             {
340                 if (m_current_song_tmp.IsSameSong(m_playlist[i]))
341                 {
342                     m_index = i;
343                     m_current_position.fromInt(m_current_song_position_tmp);
344                     m_thread_info.play = m_current_song_playing_tmp;
345                     tmp_find = true;
346                     break;
347                 }
348             }
349             m_current_song_tmp = SongInfo();
350             m_current_song_position_tmp = 0;
351             m_current_song_playing_tmp = false;
352         }
353         MusicControl(Command::OPEN);
354         MusicControl(Command::SEEK);
355         // 这行判断描述如下:m_current_song_tmp被找到时以m_current_song_playing_tmp为准,覆盖其他设置
356         // 没有找到m_current_song_tmp则当(theApp.m_play_setting_data.auto_play_when_start || m_thread_info.play)为true时播放
357         if ((theApp.m_play_setting_data.auto_play_when_start && !tmp_find) || m_thread_info.play)
358             MusicControl(Command::PLAY);
359     }
360     else
361     {
362         // 列表为空没有执行OPEN时在这里复位显示
363         m_index = 0;
364         m_current_position.fromInt(0);
365         m_song_length.fromInt(0);
366         // 清除歌词和专辑封面
367         m_album_cover.Destroy();
368         m_album_cover_blur.Destroy();
369         m_Lyrics = CLyrics();
370         m_controls.UpdateControlsMetadata(SongInfo());
371         MediaTransControlsLoadThumbnailDefaultImage();
372     }
373 
374     OnPlaylistChange();
375     AfterSetTrack();
376 
377     //初始化随机播放序号列表
378     //在OnPlaylistChange后面以免被清空
379     InitShuffleList(m_index);
380 
381     if (m_repeat_mode == RM_PLAY_RANDOM)
382         m_random_list.push_back(m_index);
383 
384     SaveRecentInfoToFiles();
385 
386     // 移除文件夹后会切入默认播放列表,但此时实际上需要刷新媒体库文件夹/播放列表两个标签页
387     if (!m_thread_info.remove_list_path.empty() && CCommon::IsFolder(m_thread_info.remove_list_path))
388         CMusicPlayerCmdHelper::RefreshMediaTabData(CMusicPlayerCmdHelper::ML_FOLDER);
389     // 刷新媒体库标签页(需要在SaveRecentInfoToFiles()之后,GetPlayStatusMutex().unlock()之前进行)
390     if (m_playlist_mode == PM_FOLDER)
391         CMusicPlayerCmdHelper::RefreshMediaTabData(CMusicPlayerCmdHelper::ML_FOLDER);
392     else if (m_playlist_mode == PM_PLAYLIST)
393         CMusicPlayerCmdHelper::RefreshMediaTabData(CMusicPlayerCmdHelper::ML_PLAYLIST);
394 
395     m_thread_info = ThreadInfo();
396     // 检查过了只是保险起见
397     ASSERT(m_loading);
398     if (m_loading) GetPlayStatusMutex().unlock();
399     m_loading = false;
400 }
401 
SearchLyrics(bool refresh)402 void CPlayer::SearchLyrics(bool refresh)
403 {
404     //检索正在播放的音频文件的歌词
405     const SongInfo& cur_song = GetCurrentSongInfo();
406     SongInfo cur_song_info{ CSongDataManager::GetInstance().GetSongInfo3(cur_song) };
407     if (cur_song_info.lyric_file == NO_LYRIC_STR && !refresh)   // 歌曲标记为没有歌词且不要求强制刷新时返回
408         return;
409 
410     wstring lyric_path;
411     if (refresh || cur_song_info.lyric_file.empty() || !CCommon::FileExist(cur_song_info.lyric_file))
412     {
413         CMusicPlayerCmdHelper helper;
414         lyric_path = helper.SearchLyricFile(cur_song, theApp.m_lyric_setting_data.lyric_fuzzy_match);
415         cur_song_info.lyric_file = lyric_path;
416         CSongDataManager::GetInstance().AddItem(cur_song_info);
417     }
418     else
419     {
420         lyric_path = cur_song_info.lyric_file;
421     }
422     GetCurrentSongInfo2().lyric_file = lyric_path;
423 }
424 
IniLyrics()425 void CPlayer::IniLyrics()
426 {
427     //尝试获取内嵌歌词
428     CLyrics inner_lyrics;		//音频文件内嵌歌词
429     wstring lyric_str;			//内嵌歌词的原始文本
430     if (theApp.m_lyric_setting_data.use_inner_lyric_first)
431     {
432         SongInfo song;
433         song.file_path = GetCurrentFilePath();
434         CAudioTag audio_tag(song, GetBassHandle());
435         lyric_str = audio_tag.GetAudioLyric();
436         inner_lyrics.LyricsFromRowString(lyric_str);
437     }
438 
439     //获取关联歌词文件的歌词
440     CLyrics file_lyrics;		//来自歌词文件
441     if (!m_playlist.empty() && !GetCurrentSongInfo().lyric_file.empty())
442     {
443         file_lyrics = CLyrics{ GetCurrentSongInfo().lyric_file };
444     }
445 
446     //判断使用内嵌歌词还是关联歌词文件的歌词
447     if (inner_lyrics.IsEmpty() && !file_lyrics.IsEmpty())
448     {
449         m_Lyrics = file_lyrics;
450         m_inner_lyric = false;
451     }
452     else if (theApp.m_lyric_setting_data.use_inner_lyric_first)
453     {
454         m_Lyrics = inner_lyrics;
455         m_inner_lyric = !lyric_str.empty();
456     }
457     else
458     {
459         m_Lyrics = CLyrics();
460         m_inner_lyric = false;
461     }
462 }
463 
IniLyrics(const wstring & lyric_path)464 void CPlayer::IniLyrics(const wstring& lyric_path)
465 {
466     m_Lyrics = CLyrics{ lyric_path };
467     GetCurrentSongInfo2().lyric_file = lyric_path;
468     SongInfo song_info{ CSongDataManager::GetInstance().GetSongInfo3(GetCurrentSongInfo()) };
469     song_info.lyric_file = lyric_path;
470     CSongDataManager::GetInstance().AddItem(song_info);
471 }
472 
473 
MusicControl(Command command,int volume_step)474 void CPlayer::MusicControl(Command command, int volume_step)
475 {
476     if (m_pCore == nullptr)
477         return;
478 
479     // VOLUME_UP和VOLUME_DOWN可在无法播放时使用
480     // stop和close也可以在m_index失效无法播放时使用(RemoveSong(s))
481     if (command != Command::VOLUME_ADJ && command != Command::STOP && command != Command::CLOSE)
482     {
483         if (!CCommon::IsURL(GetCurrentFilePath()) && !CCommon::FileExist(GetCurrentFilePath()))
484         {
485             m_error_state = ES_FILE_NOT_EXIST;
486             return;
487         }
488     }
489 
490     switch (command)
491     {
492     case Command::OPEN:
493     {
494         m_file_opend = false;
495         m_controls.ClearAll();  // Clear all metadata.
496         SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_POST_MUSIC_STREAM_OPENED, 0, 0);
497         m_error_code = 0;
498         m_error_state = ES_NO_ERROR;
499         SongInfo& cur_song = GetCurrentSongInfo2(); // 获取m_playlist[m_index]的引用,m_index无效时取得m_no_use
500         m_is_osu = COSUPlayerHelper::IsOsuFile(cur_song.file_path);
501         m_pCore->Open(cur_song.file_path.c_str());
502         GetPlayerCoreError(L"Open");
503         if (m_pCore->GetCoreType() == PT_BASS && GetBassHandle() == 0)
504             m_error_state = ES_FILE_CANNOT_BE_OPEN;
505         m_file_opend = true;
506         //获取音频类型
507         m_current_file_type = m_pCore->GetAudioType();  // 根据通道信息获取当前音频文件的类型
508         if (m_current_file_type.empty())                // 如果获取不到音频文件的类型,则将其文件扩展名作为文件类型
509         {
510             CFilePathHelper file_path{ cur_song.file_path };
511             m_current_file_type = file_path.GetFileExtension(true);
512         }
513         if (!cur_song.file_path.empty())
514         {
515             //打开时获取专辑封面
516             SearchAlbumCover();
517             //初始化歌词
518             SearchLyrics();
519             IniLyrics();
520         }
521         m_song_length = cur_song.length();
522         SetVolume();
523         if (std::fabs(m_speed - 1) > 0.01)
524             SetSpeed(m_speed);
525         SetPitch(m_pitch);
526         memset(m_spectral_data, 0, sizeof(m_spectral_data));		//打开文件时清除频谱分析的数据
527         //SetFXHandle();
528         if (m_equ_enable)
529             SetAllEqualizer();
530         if (m_reverb_enable)
531             m_pCore->SetReverb(m_reverb_mix, m_reverb_time);
532         else
533             m_pCore->ClearReverb();
534         PostMessage(theApp.m_pMainWnd->m_hWnd, WM_MUSIC_STREAM_OPENED, 0, 0);
535         m_controls.UpdateControlsMetadata(GetCurrentSongInfo());
536         m_controls.UpdateControls(PlaybackStatus::Closed);          // OPEN时设置为停止,PLAY时再设置为PLAY
537         m_enable_lastfm = theApp.m_media_lib_setting_data.enable_lastfm;
538         if (m_enable_lastfm) {
539             UpdateLastFMCurrentTrack(GetCurrentSongInfo());
540         }
541     }
542     break;
543     case Command::PLAY:
544         ConnotPlayWarning();
545         m_pCore->Play();
546         m_playing = PS_PLAYING;
547         GetPlayerCoreError(L"Play");
548         m_controls.UpdateControls(PlaybackStatus::Playing);
549         MediaTransControlsLoadThumbnailDefaultImage();
550         break;
551     case Command::CLOSE:
552         //RemoveFXHandle();
553         m_file_opend = false;   // 主窗口定时器使用此变量以阻止播放结束自动下一曲
554         m_pCore->Close();
555         m_playing = PS_STOPED;
556         SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_AFTER_MUSIC_STREAM_CLOSED, 0, 0);
557         m_controls.UpdateControls(PlaybackStatus::Closed);
558         break;
559     case Command::PAUSE:
560         m_pCore->Pause();
561         m_playing = PS_PAUSED;
562         m_controls.UpdateControls(PlaybackStatus::Paused);
563         MediaTransControlsLoadThumbnailDefaultImage();
564         break;
565     case Command::STOP:
566         if (GetCurrentSongInfo().is_cue && GetCurrentSongInfo().start_pos > 0)
567         {
568             SeekTo(0);
569             m_pCore->Pause();
570         }
571         else
572         {
573             m_pCore->Stop();
574         }
575         m_playing = PS_STOPED;
576         m_current_position = Time();
577         memset(m_spectral_data, 0, sizeof(m_spectral_data));		//停止时清除频谱分析的数据
578         m_controls.UpdateControls(PlaybackStatus::Stopped);
579         MediaTransControlsLoadThumbnailDefaultImage();
580         break;
581     case Command::FF:		//快进
582         GetPlayerCoreCurrentPosition();		//获取当前位置(毫秒)
583         m_current_position += 5000;		//每次快进5000毫秒
584         if (m_current_position > m_song_length) m_current_position -= 5000;
585         SeekTo(m_current_position.toInt());
586         break;
587     case Command::REW:		//快退
588     {
589         GetPlayerCoreCurrentPosition();		//获取当前位置(毫秒)
590         int current_position = m_current_position.toInt();
591         current_position -= 5000;		//每次快退5000毫秒
592         if (current_position < 0) current_position = 0;		//防止快退到负的位置
593         SeekTo(current_position);
594     }
595     break;
596     case Command::PLAY_PAUSE:
597         if (m_playing == PS_PLAYING)
598         {
599             m_pCore->Pause();
600             m_playing = PS_PAUSED;
601             m_controls.UpdateControls(PlaybackStatus::Paused);
602         }
603         else
604         {
605             ConnotPlayWarning();
606             m_pCore->Play();
607             m_playing = PS_PLAYING;
608             GetPlayerCoreError(L"Play");
609             m_controls.UpdateControls(PlaybackStatus::Playing);
610         }
611         MediaTransControlsLoadThumbnailDefaultImage();
612         break;
613     case Command::VOLUME_ADJ:
614         m_volume += volume_step;
615         if (m_volume > 100) m_volume = 100;
616         if (m_volume < 0) m_volume = 0;
617         SetVolume();
618         break;
619     case Command::SEEK:		//定位到m_current_position的位置
620         if (m_current_position > m_song_length)
621         {
622             m_current_position = Time();
623         }
624         SeekTo(m_current_position.toInt());
625         break;
626     default:
627         break;
628     }
629 }
630 
SongIsOver() const631 bool CPlayer::SongIsOver() const
632 {
633     if (m_pCore->SongIsOver())
634         return true;
635     if (GetCurrentSongInfo().is_cue || IsMciCore())
636         return (m_playing == PS_PLAYING && m_current_position >= m_song_length && m_current_position.toInt() != 0);
637     return false;
638 }
639 
GetPlayerCoreCurrentPosition()640 void CPlayer::GetPlayerCoreCurrentPosition()
641 {
642     int current_position_int = m_pCore->GetCurPosition();
643     if (!IsPlaylistEmpty() && GetCurrentSongInfo().is_cue)
644     {
645         current_position_int -= GetCurrentSongInfo().start_pos.toInt();
646     }
647     m_current_position.fromInt(current_position_int);
648 }
649 
650 
SetVolume()651 void CPlayer::SetVolume()
652 {
653     int volume = m_volume;
654     volume = volume * theApp.m_nc_setting_data.volume_map / 100;
655     m_pCore->SetVolume(volume);
656     GetPlayerCoreError(L"SetVolume");
657     SendMessage(theApp.m_pMainWnd->m_hWnd, WM_VOLUME_CHANGED, 0, 0);
658 }
659 
660 
CalculateSpectralData()661 void CPlayer::CalculateSpectralData()
662 {
663     //memcpy_s(m_last_spectral_data, sizeof(m_last_spectral_data), m_spectral_data, sizeof(m_spectral_data));
664 
665     if (m_pCore != nullptr && ((GetBassHandle() && m_playing != 0 && m_current_position.toInt() < m_song_length.toInt() - 500)     //确保音频句柄不为空,并且歌曲最后500毫秒不显示频谱,以防止歌曲到达末尾无法获取频谱的错误
666         || m_pCore->GetCoreType() == PT_FFMPEG) && m_pCore->GetPlayingState() != PS_STOPED)
667     {
668         int scale = (m_pCore->GetCoreType() == PT_FFMPEG ? 100 : 60);
669         m_pCore->GetFFTData(m_fft);
670         for (int i{}; i < FFT_SAMPLE; i++)
671             m_fft[i] = std::abs(m_fft[i]);
672         if (theApp.m_app_setting_data.use_old_style_specturm)
673             CSpectralDataHelper::SpectralDataMapOld(m_fft, m_spectral_data, scale);
674         else
675             m_spectrum_data_helper.SpectralDataMap(m_fft, m_spectral_data, scale);
676     }
677     else
678     {
679         memset(m_spectral_data, 0, sizeof(m_spectral_data));
680     }
681 }
682 
683 
CalculateSpectralDataPeak()684 void CPlayer::CalculateSpectralDataPeak()
685 {
686     //计算频谱顶端的高度
687     if (m_pCore != nullptr && m_pCore->GetPlayingState() != PS_PAUSED)
688     {
689         static int fall_count[SPECTRUM_COL];
690         for (int i{}; i < SPECTRUM_COL; i++)
691         {
692             if (m_spectral_data[i] > m_spectral_peak[i])
693             {
694                 m_spectral_peak[i] = m_spectral_data[i];		//如果当前的频谱比上一次的频谱高,则频谱顶端高度则为当前频谱的高度
695                 fall_count[i] = 0;
696             }
697             else if (m_spectral_data[i] < m_spectral_peak[i])
698             {
699                 fall_count[i]++;
700                 float fall_distance = fall_count[i] * (8.18824f / theApp.m_fps - 0.082353f);
701                 if (fall_distance < 0)
702                     fall_distance = 0;
703                 m_spectral_peak[i] -= fall_distance;		//如果当前频谱比上一次的频谱主低,则频谱顶端的高度逐渐下降
704             }
705         }
706     }
707 }
708 
IsPlaying() const709 bool CPlayer::IsPlaying() const
710 {
711     return m_playing == PS_PLAYING;
712 }
713 
PlayTrack(int song_track,bool auto_next)714 bool CPlayer::PlayTrack(int song_track, bool auto_next)
715 {
716     if (!auto_next)     // auto_next参数仅在主定时器被设置为true,此时已获取播放状态锁
717     {
718         if (CPlayer::GetInstance().m_loading) return false;
719         if (!CPlayer::GetInstance().GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false;
720     }
721 
722     if (song_track >= 0) {
723         m_next_tracks.clear();     //手动播放时复位下一首列表
724     }
725     bool stop{};    // 根据循环模式和参数song_track判断应当停止时设置为true
726     switch (m_repeat_mode)
727     {
728     case RM_PLAY_ORDER:		//顺序播放
729 
730         if (song_track == NEXT)		//播放下一曲
731         {
732             if (!m_next_tracks.empty()) {
733                 song_track = m_next_tracks.front();
734                 m_next_tracks.pop_front();
735             }
736             else
737             {
738                 song_track = m_index + 1;
739             }
740         }
741         else if (song_track == PREVIOUS)		//播放上一曲
742         {
743             song_track = m_index - 1;
744         }
745         break;
746 
747     case RM_PLAY_SHUFFLE:		//无序播放
748         if (m_shuffle_list.size() != m_playlist.size())
749             InitShuffleList();
750         if (!m_shuffle_list.empty())
751         {
752             if (song_track == NEXT)
753             {
754                 if (!m_next_tracks.empty()) {
755                     song_track = m_next_tracks.front();
756                     m_next_tracks.pop_front();
757                 }
758                 else
759                 {
760                     m_shuffle_index = GetNextShuffleIdx();
761                     if (m_shuffle_index == 0 && m_is_shuffle_list_played || m_shuffle_list.empty())
762                     {
763                         //如果列表中的曲目已经随机播放完了一遍,则重新生成一个新的顺序
764                         InitShuffleList();
765                         if (m_shuffle_list.empty())
766                             break;
767                     }
768                     song_track = m_shuffle_list[m_shuffle_index];
769                 }
770             }
771             else if (song_track == PREVIOUS)
772             {
773                 if (m_shuffle_list.empty())
774                     break;
775                 m_shuffle_index = GetPrevShuffleIdx();
776                 song_track = m_shuffle_list[m_shuffle_index];
777             }
778             else if (m_is_shuffle_list_played)
779             {
780                 //防止指定播放歌曲时,生成的列表第一个仍是该歌曲导致连续播放两遍
781                 InitShuffleList(song_track);      //手动指定播放曲目时重新生成无序列表
782             }
783             m_is_shuffle_list_played = true;      //否则手动指定时,可能会出现下一曲仍是同一曲
784         }
785         break;
786 
787     case RM_PLAY_RANDOM:		//随机播放
788         if (song_track == NEXT)
789         {
790             if (!m_next_tracks.empty()) {
791                 song_track = m_next_tracks.front();
792                 m_next_tracks.pop_front();
793             }
794             else
795             {
796                 if (GetSongNum() > 1)
797                 {
798                     song_track = CCommon::Random(0, GetSongNum());
799                 }
800                 else
801                 {
802                     song_track = 0;      //只有一首歌
803                 }
804             }
805             m_random_list.push_back(song_track);	//保存随机播放过的曲目
806         }
807         else if (song_track == PREVIOUS)		//回溯上一个随机播放曲目
808         {
809             if (m_random_list.size() >= 2)
810             {
811                 if (m_index == m_random_list.back())
812                     m_random_list.pop_back();
813                 song_track = m_random_list.back();
814             }
815             else
816                 stop = true;
817         }
818         else if (song_track >= 0 && song_track < GetSongNum() && song_track != m_index)     //手动指定歌曲时
819         {
820             m_random_list.push_back(song_track);	//保存随机播放过的曲目
821         }
822         break;
823 
824     case RM_LOOP_TRACK:		//单曲循环
825         if (auto_next)
826         {
827             if (song_track == NEXT)
828             {
829                 if (!m_next_tracks.empty()) {
830                     song_track = m_next_tracks.front();
831                     m_next_tracks.pop_front();
832                 }
833                 else {
834                     song_track = m_index;
835                 }
836             }
837             else if (song_track == PREVIOUS)
838                 song_track = m_index;
839         }
840         else
841         {
842             LoopPlaylist(song_track);   //如果不是播放完成后自动下一曲,则执行列表循环中的代码
843         }
844         break;
845 
846     case RM_LOOP_PLAYLIST:		//列表循环
847         if (!m_next_tracks.empty()) {
848             song_track = m_next_tracks.front();
849             m_next_tracks.pop_front();
850         }
851         else
852         {
853             LoopPlaylist(song_track);
854         }
855         break;
856 
857     case RM_PLAY_TRACK:
858         if (auto_next)
859         {
860             if (song_track == NEXT || song_track == PREVIOUS)
861                 stop = true;
862         }
863         else
864         {
865             LoopPlaylist(song_track);   //如果不是播放完成后自动下一曲,则执行列表循环中的代码
866         }
867         break;
868     }
869 
870     if (song_track < 0 || song_track >= GetSongNum())
871     {
872         song_track = 0;
873         if (auto_next)
874             stop = true;
875     }
876     if (stop)
877         MusicControl(Command::STOP);
878     else
879     {
880         m_current_position.fromInt(0);      //关闭前将当前播放位置清零
881         MusicControl(Command::CLOSE);
882         m_index = song_track;
883         MusicControl(Command::OPEN);
884         if (GetCurrentSongInfo().is_cue)
885             SeekTo(0);
886         MusicControl(Command::PLAY);
887         GetPlayerCoreCurrentPosition();
888     }
889     AfterSetTrack();
890     SaveConfig();
891     SaveRecentInfoToFiles(false);
892     if(!auto_next)
893         CPlayer::GetInstance().GetPlayStatusMutex().unlock();
894     return true;
895 }
896 
PlayAfterCurrentTrack(const std::vector<int> & tracks_to_play)897 bool CPlayer::PlayAfterCurrentTrack(const std::vector<int>& tracks_to_play)
898 {
899     bool add{ false };
900     for (auto it = tracks_to_play.rbegin(); it != tracks_to_play.rend(); ++it)  // 为维持次序不变此处逆序遍历
901     {
902         const int& track = *it;
903         if (track >= 0 && track < static_cast<int>(m_playlist.size()))
904         {
905             m_next_tracks.push_front(track);
906             add = true;
907         }
908     }
909     return add;
910 }
911 
PlayAfterCurrentTrack(const std::vector<SongInfo> & tracks_to_play)912 bool CPlayer::PlayAfterCurrentTrack(const std::vector<SongInfo>& tracks_to_play)
913 {
914     bool add{ false };
915     for (auto it = tracks_to_play.rbegin(); it != tracks_to_play.rend(); ++it)  // 为维持次序不变此处逆序遍历
916     {
917         int index = IsSongInPlayList(*it);
918         if(index != -1)
919         {
920             m_next_tracks.push_front(index);
921             add = true;
922         }
923     }
924     return add;
925 }
926 
LoopPlaylist(int & song_track)927 void CPlayer::LoopPlaylist(int& song_track)
928 {
929     if (song_track == NEXT)		//播放下一曲
930     {
931         song_track = m_index + 1;
932         if (song_track >= GetSongNum()) song_track = 0;
933         if (song_track < 0) song_track = GetSongNum() - 1;
934     }
935     if (song_track == PREVIOUS)		//播放上一曲
936     {
937         song_track = m_index - 1;
938         if (song_track >= GetSongNum()) song_track = 0;
939         if (song_track < 0) song_track = GetSongNum() - 1;
940     }
941 }
942 
SaveRecentInfoToFiles(bool save_playlist)943 void CPlayer::SaveRecentInfoToFiles(bool save_playlist)
944 {
945     static bool initialized{ false };
946     // 程序启动后第一次调用时不需要保存(m_playlist为空时进行播放列表保存会导致清空列表)
947     if (!initialized)
948     {
949         initialized = true;
950         return;
951     }
952     int song_num = IsPlaylistEmpty() ? 0 : GetSongNum();
953 
954     // CPlayer应当持有一个此对象代替零散变量
955     ListItem list_item{};
956 
957     if (m_playlist_mode == PM_PLAYLIST)
958     {
959         if (save_playlist)
960             SaveCurrentPlaylist();
961         list_item.type = ListType::LT_PLAYLIST;
962         list_item.path = m_playlist_path;
963     }
964     else if (m_playlist_mode == PM_MEDIA_LIB)
965     {
966         list_item.type = ListType::LT_MEDIA_LIB;
967         list_item.medialib_type = m_media_lib_playlist_type;
968         list_item.path = m_media_lib_playlist_name;
969     }
970     else if (m_playlist_mode == PM_FOLDER)
971     {
972         list_item.type = ListType::LT_FOLDER;
973         list_item.path = m_path;
974         list_item.contain_sub_folder = m_contain_sub_folder;
975     }
976     list_item.sort_mode = m_sort_mode;
977     list_item.last_track = GetCurrentSongInfo();
978     list_item.last_position = GetCurrentPosition();
979     list_item.total_time = m_total_time;
980     list_item.total_num = song_num;
981     CRecentList::Instance().SetCurrentList(list_item);
982     CRecentList::Instance().SaveData();
983 }
984 
BeforeIniPlayList(bool continue_play,bool force_continue_play)985 bool CPlayer::BeforeIniPlayList(bool continue_play, bool force_continue_play)
986 {
987     if (m_loading) return false;
988     if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false;
989     m_loading = true;
990     IniPlayerCore();
991     SaveRecentInfoToFiles();
992     // 实现同曲目播放保持
993     if ((continue_play && theApp.m_play_setting_data.continue_when_switch_playlist) || force_continue_play)
994     {
995         m_current_song_tmp = GetCurrentSongInfo();
996         m_current_song_position_tmp = GetCurrentPosition();
997         m_current_song_playing_tmp = IsPlaying();
998     }
999     MusicControl(Command::CLOSE);
1000     return true;
1001 }
1002 
1003 #pragma region 列表初始化方法
1004 
SetList(ListItem list_item,bool play,bool force)1005 bool CPlayer::SetList(ListItem list_item, bool play, bool force)
1006 {
1007     if (!BeforeIniPlayList(!force))
1008         return false;
1009 
1010     SongKey play_song{};
1011     if (force)
1012         play_song = list_item.last_track;
1013     CRecentList::Instance().LoadItem(list_item);
1014     if (!force)
1015     {
1016         play_song = list_item.last_track;
1017         m_current_position.fromInt(list_item.last_position);
1018     }
1019 
1020     switch (list_item.type)
1021     {
1022     case LT_FOLDER:
1023         m_path = list_item.path;
1024         m_playlist_path.clear();
1025         m_playlist_mode = PM_FOLDER;
1026         m_sort_mode = list_item.GetDefaultSortMode();
1027         m_contain_sub_folder = list_item.contain_sub_folder;
1028         m_index = 0;
1029         m_media_lib_playlist_type = {};
1030         m_media_lib_playlist_name.clear();
1031         break;
1032     case LT_PLAYLIST:
1033         m_path = {};
1034         m_playlist_path = list_item.path;
1035         m_playlist_mode = PM_PLAYLIST;
1036         m_sort_mode = SM_UNSORT;//list_item.GetDefaultSortMode();   // 考虑今后允许播放列表维持排序状态,ui怎样设计(菜单)还没想好
1037         m_contain_sub_folder = {};
1038         m_index = 0;
1039         m_media_lib_playlist_type = {};
1040         m_media_lib_playlist_name.clear();
1041         break;
1042     case LT_MEDIA_LIB:
1043         m_path = {};
1044         m_playlist_path = {};
1045         m_playlist_mode = PM_MEDIA_LIB;
1046         m_sort_mode = list_item.GetDefaultSortMode();
1047         m_contain_sub_folder = false;
1048         m_index = 0;
1049         m_media_lib_playlist_type = list_item.medialib_type;
1050         m_media_lib_playlist_name = list_item.path;
1051         break;
1052     default:
1053         ASSERT(FALSE);
1054         break;
1055     }
1056 
1057     if (!IsPlaylistMode() && !play_song.path.empty())
1058         m_current_song_tmp = CSongDataManager::GetInstance().GetSongInfo(play_song);
1059     m_current_song_position_tmp = list_item.last_position;
1060 
1061     IniPlayList(play, {}, play_song);
1062     return true;
1063 }
1064 
1065 
OpenFolder(wstring path,bool contain_sub_folder,bool play)1066 bool CPlayer::OpenFolder(wstring path, bool contain_sub_folder, bool play)
1067 {
1068     if (!BeforeIniPlayList())
1069         return false;
1070 
1071     // 按照新文件夹设置
1072     m_path = path;
1073     m_playlist_path.clear();
1074     m_playlist_mode = PM_FOLDER;
1075     m_sort_mode = SM_U_FILE;
1076     m_contain_sub_folder = contain_sub_folder;
1077     m_index = 0;
1078     m_current_position.fromInt(0);
1079 
1080     // 如果是打开过的文件夹那么用保存的设置覆盖默认值
1081     ListItem list_item{ LT_FOLDER, m_path };
1082     if (CRecentList::Instance().LoadItem(list_item))
1083     {
1084         m_sort_mode = list_item.sort_mode;
1085         m_index = 0;
1086         m_current_position.fromInt(list_item.last_position);
1087     }
1088 
1089     IniPlayList(play, {}, list_item.last_track);
1090     return true;
1091 }
1092 
SetPlaylist(const wstring & playlist_path,int track,int position,bool play,bool force)1093 bool CPlayer::SetPlaylist(const wstring& playlist_path, int track, int position, bool play, bool force)
1094 {
1095     if (!BeforeIniPlayList(!force))
1096         return false;
1097 
1098     m_path.clear();
1099     m_playlist_path = playlist_path;
1100     m_playlist_mode = PM_PLAYLIST;
1101     m_sort_mode = SM_UNSORT;    // 播放列表模式下默认未排序
1102     m_contain_sub_folder = false;
1103     m_index = track;
1104     m_current_position.fromInt(position);
1105 
1106     IniPlayList(play);
1107     return true;
1108 }
1109 
OpenPlaylistFile(wstring & file_path)1110 bool CPlayer::OpenPlaylistFile(wstring& file_path)
1111 {
1112     CFilePathHelper helper(file_path);
1113     ListItem list_item{ LT_PLAYLIST, file_path };
1114     if (helper.GetDir() == theApp.m_playlist_dir && helper.GetFileExtension() == PLAYLIST_EXTENSION_2)
1115     {
1116         return SetList(list_item);
1117     }
1118     // 如果打开的播放列表文件不是程序默认的播放列表目录,则将其转换为*.playlist格式并复制到默认的播放列表目录
1119     wstring playlist_name = helper.GetFileNameWithoutExtension();
1120     wstring new_path = theApp.m_playlist_dir + playlist_name + PLAYLIST_EXTENSION;
1121     CCommon::FileAutoRename(new_path);
1122 
1123     CPlaylistFile playlist;
1124     playlist.LoadFromFile(file_path);
1125     playlist.SaveToFile(new_path);
1126     file_path = new_path;
1127     list_item.path = new_path;
1128     return SetList(list_item);
1129 }
1130 
OpenFilesInDefaultPlaylist(const vector<wstring> & files,bool play)1131 bool CPlayer::OpenFilesInDefaultPlaylist(const vector<wstring>& files, bool play)
1132 {
1133     vector<SongInfo> songs(files.size());
1134     for (size_t i{}; i < files.size(); ++i)
1135         songs[i].file_path = files[i];
1136     return OpenSongsInDefaultPlaylist(songs, play);
1137 }
1138 
OpenSongsInDefaultPlaylist(const vector<SongInfo> & songs,bool play)1139 bool CPlayer::OpenSongsInDefaultPlaylist(const vector<SongInfo>& songs, bool play)
1140 {
1141     if (songs.empty()) return false;
1142     if (!BeforeIniPlayList())
1143         return false;
1144 
1145     m_path.clear();
1146     m_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_DEFAULT).path;
1147     m_playlist_mode = PM_PLAYLIST;
1148     m_sort_mode = SM_UNSORT;    // 播放列表模式下默认未排序
1149     m_contain_sub_folder = false;
1150     m_index = 0;
1151     m_current_position.fromInt(0);
1152 
1153     // 向播放列表文件追加songs
1154     CPlaylistFile playlist;
1155     playlist.LoadFromFile(m_playlist_path);
1156     playlist.AddSongsToPlaylist(songs, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
1157     playlist.SaveToFile(m_playlist_path);
1158     // 设置播放songs的第一个文件
1159     m_index = playlist.GetSongIndexInPlaylist(songs.front());
1160 
1161     IniPlayList(play);
1162     return true;
1163 }
1164 
OpenSongsInTempPlaylist(const vector<SongInfo> & songs,int play_index,bool play)1165 bool CPlayer::OpenSongsInTempPlaylist(const vector<SongInfo>& songs, int play_index, bool play /*= true*/)
1166 {
1167     if (songs.empty()) return false;
1168     if (!BeforeIniPlayList())
1169         return false;
1170 
1171     m_path.clear();
1172     m_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_TEMP).path;
1173     m_playlist_mode = PM_PLAYLIST;
1174     m_sort_mode = SM_UNSORT;    // 播放列表模式下默认未排序
1175     m_contain_sub_folder = false;
1176     m_index = play_index;
1177     m_current_position.fromInt(0);
1178 
1179     // 向播放列表文件覆写songs
1180     CPlaylistFile::SavePlaylistToFile(songs, m_playlist_path);
1181 
1182     IniPlayList(play);
1183     return true;
1184 }
1185 
OpenASongInFolderMode(const SongInfo & song,bool play)1186 bool CPlayer::OpenASongInFolderMode(const SongInfo& song, bool play)
1187 {
1188     if (song.file_path.empty()) return false;
1189     if (!BeforeIniPlayList())
1190         return false;
1191 
1192     CFilePathHelper file_path(song.file_path);
1193     m_path = file_path.GetDir();
1194     m_playlist_path.clear();
1195     m_playlist_mode = PM_FOLDER;
1196     m_sort_mode = SM_U_FILE;
1197     m_contain_sub_folder = false;
1198     m_index = 0;
1199     m_current_position.fromInt(0);
1200 
1201     // 如果是打开过的文件夹那么用保存的设置覆盖默认值
1202     ListItem list_item{ LT_FOLDER, m_path };
1203     if (CRecentList::Instance().LoadItem(list_item))
1204     {
1205         m_sort_mode = list_item.sort_mode;
1206         m_contain_sub_folder = list_item.contain_sub_folder;
1207         m_index = 0;
1208         m_current_position.fromInt(list_item.last_position);
1209     }
1210     // 使用切换播放列表继续播放实现初始化线程后的指定歌曲播放
1211     m_current_song_tmp = song;
1212     m_current_song_position_tmp = 0;
1213     m_current_song_playing_tmp = play;
1214 
1215     IniPlayList(play, {}, list_item.last_track);
1216     return true;
1217 }
1218 
AddFilesToPlaylist(const vector<wstring> & files)1219 int CPlayer::AddFilesToPlaylist(const vector<wstring>& files)
1220 {
1221     vector<SongInfo> songs(files.size());
1222     for (size_t i{}; i < files.size(); ++i)
1223         songs[i].file_path = files[i];
1224     return AddSongsToPlaylist(songs);
1225 }
1226 
AddSongsToPlaylist(const vector<SongInfo> & songs)1227 int CPlayer::AddSongsToPlaylist(const vector<SongInfo>& songs)
1228 {
1229     // 此方法仅限已处于播放列表模式时使用
1230     if (m_playlist_mode != PM_PLAYLIST || m_playlist_path.empty()) return -2;
1231     // 这里有必要暂时关闭,故保存播放状态,AddSongsToPlaylist可能将歌曲插入到开头导致index不再准确
1232     // 待到将来万一m_playlist的多线程问题彻底修好以后或许可以做不停止的重新初始化
1233     if (!BeforeIniPlayList(true, true))
1234         return -1;
1235 
1236     // 向当前播放列表文件追加songs
1237     CPlaylistFile playlist;
1238     playlist.LoadFromFile(m_playlist_path);
1239     int added = playlist.AddSongsToPlaylist(songs, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
1240     playlist.SaveToFile(m_playlist_path);
1241 
1242     m_sort_mode = SM_UNSORT;        // 播放列表模式下的修改会失去排序状态
1243     m_index = 0;
1244     m_current_position.fromInt(0);
1245 
1246     IniPlayList();
1247     return added;
1248 }
1249 
ReloadPlaylist(MediaLibRefreshMode refresh_mode)1250 bool CPlayer::ReloadPlaylist(MediaLibRefreshMode refresh_mode)
1251 {
1252     if (!BeforeIniPlayList(true, true))
1253         return false;
1254 
1255     if (IsPlaylistMode())
1256         m_sort_mode = SM_UNSORT;        // 播放列表模式默认未排序
1257     m_index = 0;
1258     m_current_position.fromInt(0);
1259 
1260     IniPlayList(false, refresh_mode);
1261     return true;
1262 }
1263 
SetContainSubFolder()1264 bool CPlayer::SetContainSubFolder()
1265 {
1266     if (m_playlist_mode == PM_FOLDER)
1267     {
1268         m_contain_sub_folder = !m_contain_sub_folder;
1269         if (ReloadPlaylist(MR_MIN_REQUIRED))
1270             return true;
1271         else
1272         {
1273             m_contain_sub_folder = !m_contain_sub_folder;   // ReloadPlaylist失败则此次翻转撤销,并返回false
1274             return false;
1275         }
1276     }
1277     return true;    // 播放列表模式返回true
1278 }
1279 
RemoveCurPlaylistOrFolder()1280 bool CPlayer::RemoveCurPlaylistOrFolder()
1281 {
1282     if (!BeforeIniPlayList(true))
1283         return false;
1284 
1285     if (m_playlist_mode == PM_MEDIA_LIB)
1286         return false;
1287 
1288     // 在列表初始化线程中通知主窗口移除当前列表
1289     if (m_playlist_mode == PM_PLAYLIST)
1290         m_thread_info.remove_list_path = m_playlist_path;
1291     else if (m_playlist_mode == PM_FOLDER)
1292         m_thread_info.remove_list_path = m_path;
1293 
1294     ListItem list_item = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_DEFAULT);
1295 
1296     m_path.clear();
1297     m_playlist_path = list_item.path;
1298     m_playlist_mode = PM_PLAYLIST;
1299     m_sort_mode = SM_UNSORT;        // 播放列表模式默认未排序
1300     m_contain_sub_folder = false;
1301     m_index = 0;
1302     m_current_position.fromInt(list_item.last_position);
1303 
1304     IniPlayList({}, {}, list_item.last_track);
1305     return true;
1306 }
1307 
1308 #pragma endregion 列表初始化方法
1309 
SetRepeatMode()1310 void CPlayer::SetRepeatMode()
1311 {
1312     int repeat_mode{ static_cast<int>(m_repeat_mode) };
1313     repeat_mode++;
1314     if (repeat_mode >= RM_MAX)
1315         repeat_mode = 0;
1316     m_repeat_mode = static_cast<RepeatMode>(repeat_mode);
1317     SaveConfig();
1318 }
1319 
SetRepeatMode(RepeatMode repeat_mode)1320 void CPlayer::SetRepeatMode(RepeatMode repeat_mode)
1321 {
1322     m_repeat_mode = repeat_mode;
1323     SaveConfig();
1324 }
1325 
GetRepeatMode() const1326 RepeatMode CPlayer::GetRepeatMode() const
1327 {
1328     return m_repeat_mode;
1329 }
1330 
SpeedUp()1331 void CPlayer::SpeedUp()
1332 {
1333     if (m_speed < MAX_PLAY_SPEED)
1334     {
1335         if (m_speed == MIN_PLAY_SPEED)
1336             m_speed = 0.25f;
1337         else
1338             m_speed += 0.25f;
1339         if (m_speed > MAX_PLAY_SPEED)
1340             m_speed = MAX_PLAY_SPEED;
1341         if (std::fabs(m_speed - 1) < 0.01)
1342             m_speed = 1;
1343         m_pCore->SetSpeed(m_speed);
1344         m_controls.UpdateSpeed(m_speed);
1345     }
1346 }
1347 
SlowDown()1348 void CPlayer::SlowDown()
1349 {
1350     if (m_speed > MIN_PLAY_SPEED)
1351     {
1352         m_speed -= 0.25f;
1353         if (m_speed < MIN_PLAY_SPEED)
1354             m_speed = MIN_PLAY_SPEED;
1355         if (std::fabs(m_speed - 1) < 0.01)
1356             m_speed = 1;
1357         m_pCore->SetSpeed(m_speed);
1358         m_controls.UpdateSpeed(m_speed);
1359     }
1360 }
1361 
SetSpeed(float speed)1362 void CPlayer::SetSpeed(float speed) {
1363     if (speed > MIN_PLAY_SPEED && speed < MAX_PLAY_SPEED) {
1364         m_speed = speed;
1365         m_pCore->SetSpeed(m_speed);
1366         m_controls.UpdateSpeed(m_speed);
1367     }
1368 }
1369 
SetOrignalSpeed()1370 void CPlayer::SetOrignalSpeed()
1371 {
1372     m_speed = 1;
1373     m_pCore->SetSpeed(m_speed);
1374     m_controls.UpdateSpeed(m_speed);
1375 }
1376 
PitchUp()1377 void CPlayer::PitchUp()
1378 {
1379     if (m_pitch < MAX_PLAY_PITCH)
1380     {
1381         m_pitch += 1;
1382         m_pCore->SetPitch(m_pitch);
1383     }
1384 }
1385 
PitchDown()1386 void CPlayer::PitchDown()
1387 {
1388     if (m_pitch > MIN_PLAY_PITCH)
1389     {
1390         m_pitch -= 1;
1391         m_pCore->SetPitch(m_pitch);
1392     }
1393 }
1394 
SetPitch(int pitch)1395 void CPlayer::SetPitch(int pitch)
1396 {
1397     if (pitch > MIN_PLAY_PITCH && pitch < MAX_PLAY_PITCH)
1398     {
1399         m_pitch = pitch;
1400         m_pCore->SetPitch(m_pitch);
1401     }
1402 }
1403 
SetOrignalPitch()1404 void CPlayer::SetOrignalPitch()
1405 {
1406     m_pitch = 0;
1407     m_pCore->SetPitch(m_pitch);
1408 }
1409 
GetPlayerCoreError(const wchar_t * function_name)1410 bool CPlayer::GetPlayerCoreError(const wchar_t* function_name)
1411 {
1412     if (m_loading)
1413         return false;
1414     int error_code_tmp = m_pCore->GetErrorCode();
1415     if (error_code_tmp && error_code_tmp != m_error_code)
1416     {
1417         wstring log_info = m_pCore->GetErrorInfo(error_code_tmp);
1418         log_info += L" function name: ";
1419         log_info += function_name;
1420         theApp.WriteLog(log_info);
1421     }
1422     m_error_code = error_code_tmp;
1423     return true;
1424 }
1425 
IsError() const1426 bool CPlayer::IsError() const
1427 {
1428     if (m_loading)		//如果播放列表正在加载,则不检测错误
1429         return false;
1430     else
1431         return (m_error_state != ES_NO_ERROR || m_error_code != 0 || m_pCore == nullptr || (m_file_opend && m_pCore->GetCoreType() == PT_BASS && GetBassHandle() == 0));
1432 }
1433 
GetErrorInfo()1434 std::wstring CPlayer::GetErrorInfo()
1435 {
1436     wstring error_info;
1437     if (m_error_state == ES_FILE_NOT_EXIST)
1438         error_info = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_ERROR_FILE_NOT_EXIST");
1439     else if (m_error_state == ES_FILE_CANNOT_BE_OPEN)
1440         error_info = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_ERROR_FILE_CANNOT_BE_OPEND");
1441     else
1442         error_info = m_pCore->GetErrorInfo();
1443     error_info = theApp.m_str_table.LoadTextFormat(L"UI_TXT_PLAYSTATUS_ERROR_2", { error_info });
1444     return error_info;
1445 }
1446 
AfterSetTrack() const1447 void CPlayer::AfterSetTrack() const
1448 {
1449     SendMessage(theApp.m_pMainWnd->m_hWnd, WM_AFTER_SET_TRACK, 0, 0);
1450 }
1451 
SaveConfig() const1452 void CPlayer::SaveConfig() const
1453 {
1454     CIniHelper ini(theApp.m_config_path);
1455 
1456     //ini.WriteString(L"config", L"path", m_path.c_str());
1457     //ini.WriteInt(L"config", L"track", m_index);
1458     ini.WriteInt(L"config", L"volume", m_volume);
1459     //ini.WriteInt(L"config", L"position", current_position_int);
1460     ini.WriteInt(L"config", L"repeat_mode", static_cast<int>(m_repeat_mode));
1461     ini.WriteBool(L"config", L"lyric_karaoke_disp", theApp.m_lyric_setting_data.lyric_karaoke_disp);
1462     ini.WriteString(L"config", L"lyric_path", theApp.m_lyric_setting_data.lyric_path);
1463     ini.WriteInt(L"config", L"sort_mode", static_cast<int>(m_sort_mode));
1464     ini.WriteBool(L"config", L"lyric_fuzzy_match", theApp.m_lyric_setting_data.lyric_fuzzy_match);
1465     ini.WriteString(L"config", L"default_album_file_name", CCommon::StringMerge(theApp.m_app_setting_data.default_album_name, L','));
1466     ini.WriteString(L"config", L"album_cover_path", theApp.m_app_setting_data.album_cover_path);
1467     // ini.WriteInt(L"config", L"playlist_mode", m_playlist_mode);
1468     ini.WriteDouble(L"config", L"speed", m_speed);
1469     ini.WriteInt(L"config", L"pitch", m_pitch);
1470 
1471     //保存均衡器设定
1472     ini.WriteBool(L"equalizer", L"equalizer_enable", m_equ_enable);
1473     //保存每个均衡器通道的增益
1474     //if (m_equ_style == 9)
1475     //{
1476     //	wchar_t buff[16];
1477     //	for (int i{}; i < EQU_CH_NUM; i++)
1478     //	{
1479     //		swprintf_s(buff, L"channel%d", i + 1);
1480     //		ini.WriteInt(L"equalizer", buff, m_equalizer_gain[i]);
1481     //	}
1482     //}
1483     //保存混响设定
1484     ini.WriteInt(L"reverb", L"reverb_enable", m_reverb_enable);
1485     ini.WriteInt(L"reverb", L"reverb_mix", m_reverb_mix);
1486     ini.WriteInt(L"reverb", L"reverb_time", m_reverb_time);
1487 
1488     ini.Save();
1489 }
1490 
LoadConfig()1491 void CPlayer::LoadConfig()
1492 {
1493     CIniHelper ini(theApp.m_config_path);
1494 
1495     //ini.GetString(L"config", L"path", L".\\songs\\");
1496     //m_path = buff;
1497     //m_index =ini.GetInt(L"config", L"track", 0);
1498     m_volume = ini.GetInt(L"config", L"volume", 60);
1499     //current_position_int =ini.GetInt(L"config", L"position", 0);
1500     //m_current_position.fromInt(current_position_int);
1501     m_repeat_mode = static_cast<RepeatMode>(ini.GetInt(L"config", L"repeat_mode", 0));
1502     theApp.m_lyric_setting_data.lyric_path = ini.GetString(L"config", L"lyric_path", L".\\lyrics\\");
1503     if (!theApp.m_lyric_setting_data.lyric_path.empty() && theApp.m_lyric_setting_data.lyric_path.back() != L'/' && theApp.m_lyric_setting_data.lyric_path.back() != L'\\')
1504         theApp.m_lyric_setting_data.lyric_path.append(1, L'\\');
1505     theApp.m_lyric_setting_data.lyric_karaoke_disp = ini.GetBool(L"config", L"lyric_karaoke_disp", true);
1506     m_sort_mode = static_cast<SortMode>(ini.GetInt(L"config", L"sort_mode", 0));
1507     theApp.m_lyric_setting_data.lyric_fuzzy_match = ini.GetBool(L"config", L"lyric_fuzzy_match", true);
1508     wstring default_album_name = ini.GetString(L"config", L"default_album_file_name", L"cover");
1509     CCommon::StringSplit(default_album_name, L',', theApp.m_app_setting_data.default_album_name);
1510 
1511     theApp.m_app_setting_data.album_cover_path = ini.GetString(L"config", L"album_cover_path", L".\\cover\\");
1512     if (!theApp.m_app_setting_data.album_cover_path.empty() && theApp.m_app_setting_data.album_cover_path.back() != L'/' && theApp.m_app_setting_data.album_cover_path.back() != L'\\')
1513         theApp.m_app_setting_data.album_cover_path.append(1, L'\\');
1514 
1515     // 此项弃用不再保存,使用CRecentList记录的最近播放列表代替
1516     // bool playlist_mode_default = !CCommon::FileExist(theApp.m_recent_path_dat_path);
1517     // m_playlist_mode = static_cast<PlaylistMode>(ini.GetInt(L"config", L"playlist_mode", playlist_mode_default));
1518     m_speed = static_cast<float>(ini.GetDouble(L"config", L"speed", 1));
1519     if (m_speed < MIN_PLAY_SPEED || m_speed > MAX_PLAY_SPEED)
1520         m_speed = 1;
1521     m_pitch = static_cast<int>(ini.GetInt(L"config", L"pitch", 0));
1522     if (m_pitch < MIN_PLAY_PITCH || m_pitch > MAX_PLAY_PITCH)
1523         m_pitch = 0;
1524     //读取均衡器设定
1525     m_equ_enable = ini.GetBool(L"equalizer", L"equalizer_enable", false);
1526     m_equ_style = ini.GetInt(L"equalizer", L"equalizer_style", 0);	//读取均衡器预设
1527     if (m_equ_style == 9)		//如果均衡器预设为“自定义”
1528     {
1529         //读取每个均衡器通道的增益
1530         for (int i{}; i < EQU_CH_NUM; i++)
1531         {
1532             wchar_t buff[16];
1533             swprintf_s(buff, L"channel%d", i + 1);
1534             m_equalizer_gain[i] = ini.GetInt(L"equalizer", buff, 0);
1535         }
1536     }
1537     else if (m_equ_style >= 0 && m_equ_style < 9)		//否则,根据均衡器预设设置每个通道的增益
1538     {
1539         for (int i{}; i < EQU_CH_NUM; i++)
1540         {
1541             m_equalizer_gain[i] = EQU_STYLE_TABLE[m_equ_style][i];
1542         }
1543     }
1544     //读取混响设定
1545     m_reverb_enable = ini.GetBool(L"reverb", L"reverb_enable", 0);
1546     m_reverb_mix = ini.GetInt(L"reverb", L"reverb_mix", 45);		//混响强度默认为50
1547     m_reverb_time = ini.GetInt(L"reverb", L"reverb_time", 100);	//混响时间默认为1s
1548 }
1549 
ExplorePath(int track) const1550 void CPlayer::ExplorePath(int track) const
1551 {
1552     if (GetSongNum() > 0)
1553     {
1554         CString str;
1555         if (track < 0)		//track小于0,打开资源管理器后选中当前播放的文件
1556             str.Format(_T("/select,\"%s\""), GetCurrentFilePath().c_str());
1557         else if (track < GetSongNum())		//track为播放列表中的一个序号,打开资源管理器后选中指定的文件
1558             str.Format(_T("/select,\"%s\""), m_playlist[track].file_path.c_str());
1559         else								//track超过播放列表中文件的数量,打开资源管理器后不选中任何文件
1560             str = m_path.c_str();
1561         ShellExecute(NULL, _T("open"), _T("explorer"), str, NULL, SW_SHOWNORMAL);
1562     }
1563 }
1564 
ExploreLyric() const1565 void CPlayer::ExploreLyric() const
1566 {
1567     if (!m_Lyrics.IsEmpty())
1568     {
1569         CString str;
1570         str.Format(_T("/select,\"%s\""), m_Lyrics.GetPathName().c_str());
1571         ShellExecute(NULL, _T("open"), _T("explorer"), str, NULL, SW_SHOWNORMAL);
1572     }
1573 }
1574 
IsSongInPlayList(const SongInfo & song)1575 int CPlayer::IsSongInPlayList(const SongInfo& song)
1576 {
1577     auto iter = std::find_if(m_playlist.begin(), m_playlist.end(),
1578         [&](const SongInfo& songinfo) { return song.IsSameSong(songinfo); });
1579     if (iter != m_playlist.end())
1580         return iter - m_playlist.begin();
1581     return -1;
1582 }
1583 
IsSongsInPlayList(const vector<SongInfo> & songs_list)1584 bool CPlayer::IsSongsInPlayList(const vector<SongInfo>& songs_list)
1585 {
1586     for (const SongInfo& song : songs_list)
1587     {
1588         auto iter = std::find_if(m_playlist.begin(), m_playlist.end(),
1589             [&](const SongInfo& songinfo) { return song.IsSameSong(songinfo); });
1590         if (iter == m_playlist.end())
1591             return false;
1592     }
1593     return true;    // 没有找到不存在于m_playlist中的songs_list元素,返回true
1594 }
1595 
GetSongNum() const1596 int CPlayer::GetSongNum() const
1597 {
1598     return static_cast<int>(m_playlist.size());
1599 }
1600 
GetCurrentDir() const1601 wstring CPlayer::GetCurrentDir() const
1602 {
1603     wstring current_file_path = GetCurrentFilePath();
1604     CFilePathHelper path_helper(current_file_path);
1605     return path_helper.GetDir();
1606 }
1607 
GetCurrentDir2() const1608 wstring CPlayer::GetCurrentDir2() const
1609 {
1610     if (m_playlist_mode == PM_PLAYLIST || m_playlist_mode == PM_MEDIA_LIB)
1611         return GetCurrentDir();
1612     else
1613         return m_path;
1614 }
1615 
GetCurrentFilePath() const1616 wstring CPlayer::GetCurrentFilePath() const
1617 {
1618     if (m_index >= 0 && m_index < GetSongNum())
1619     {
1620         //if (m_playlist[m_index].file_path.empty())
1621         //    return m_path + m_playlist[m_index].file_name;
1622         //else
1623         return m_playlist[m_index].file_path;
1624     }
1625     else
1626         return wstring();
1627 }
1628 
GetDisplayName() const1629 wstring CPlayer::GetDisplayName() const
1630 {
1631     const SongInfo& song = GetCurrentSongInfo();
1632     if (song.is_cue && !song.IsArtistEmpty() && !song.IsTitleEmpty())
1633         return song.artist + L" - " + song.title;
1634     if (IsOsuFile() && !song.comment.empty())
1635         return song.comment;
1636     wstring file_name = GetCurrentSongInfo().GetFileName();
1637     if (!file_name.empty())
1638         return file_name;
1639     return theApp.m_str_table.LoadText(L"TXT_EMPTY_FILE_NAME");
1640 }
1641 
GetAlbumCover()1642 CImage& CPlayer::GetAlbumCover()
1643 {
1644     CSingleLock sync(&m_album_cover_sync, TRUE);
1645     return m_album_cover;
1646 }
1647 
GetAlbumCoverBlur()1648 ATL::CImage& CPlayer::GetAlbumCoverBlur()
1649 {
1650     CSingleLock sync(&m_album_cover_sync, TRUE);
1651     return m_album_cover_blur;
1652 }
1653 
AlbumCoverExist()1654 bool CPlayer::AlbumCoverExist()
1655 {
1656     CSingleLock slock(&m_album_cover_sync);
1657     if (slock.IsLocked())
1658         return false;
1659     else
1660         return !m_album_cover.IsNull();
1661 }
1662 
GetAlbumCoverType() const1663 wstring CPlayer::GetAlbumCoverType() const
1664 {
1665     // TagLibHelper.cpp中GetPicType的反向方法,之后需要重构,跳过int转手
1666     switch (m_album_cover_type)
1667     {
1668     case 0: return L"jpg";
1669     case 1: return L"png";
1670     case 2: return L"gif";
1671     case 3: return L"bmp";
1672     default: return L"other";
1673     }
1674 }
1675 
AfterRemoveSong(bool is_current)1676 void CPlayer::AfterRemoveSong(bool is_current)
1677 {
1678     if (is_current)
1679     {
1680         if (m_playlist.empty()) // 播放列表为空时清除显示
1681         {
1682             MusicControl(Command::CLOSE);
1683             m_playlist.push_back(SongInfo());
1684             m_index = 0;
1685             m_current_position.fromInt(0);
1686             m_song_length.fromInt(0);
1687             m_album_cover.Destroy();
1688             m_album_cover_blur.Destroy();
1689             m_Lyrics = CLyrics();
1690             m_controls.UpdateControlsMetadata(SongInfo());
1691             MediaTransControlsLoadThumbnailDefaultImage();
1692         }
1693         else    // 播放列表不为空时先确保索引有效再打开/播放(最接近的曲目)
1694         {
1695             if (m_index < 0) m_index = 0;
1696             if (m_index >= GetSongNum()) m_index = GetSongNum() - 1;
1697             bool play{ IsPlaying() };
1698             m_current_position.fromInt(0);      //关闭前将当前播放位置清零
1699             MusicControl(Command::CLOSE);
1700             MusicControl(Command::OPEN);
1701             if (GetCurrentSongInfo().is_cue)
1702                 SeekTo(0);
1703             if (play)
1704                 MusicControl(Command::PLAY);
1705             GetPlayerCoreCurrentPosition();
1706         }
1707     }
1708     // 重新统计列表总时长
1709     m_total_time = 0;
1710     for (const auto& song : m_playlist)
1711     {
1712         m_total_time += song.length().toInt();
1713     }
1714     OnPlaylistChange();
1715     AfterSetTrack();
1716     SaveRecentInfoToFiles();
1717     // 文件夹模式“从磁盘删除”时刷新媒体库路径标签页否则刷新播放列表标签页
1718     if (m_playlist_mode == PM_PLAYLIST)
1719         CMusicPlayerCmdHelper::RefreshMediaTabData(CMusicPlayerCmdHelper::ML_PLAYLIST);
1720     else if (m_playlist_mode == PM_FOLDER)
1721         CMusicPlayerCmdHelper::RefreshMediaTabData(CMusicPlayerCmdHelper::ML_FOLDER);
1722 }
1723 
RemoveSong(int index,bool skip_locking)1724 bool CPlayer::RemoveSong(int index, bool skip_locking)
1725 {
1726     if (IsPlaylistEmpty()) return false;                    // 播放列表为空(或有一个占位SongInfo)返回
1727     // if (!m_playlist_mode) return false;                     // 不是播放列表模式返回(文件夹模式可以“从磁盘删除”)
1728     if (index < 0 || index >= GetSongNum()) return false;   // index无效返回
1729     if (m_loading) return false;                            // 播放列表载入中返回
1730     if (!skip_locking)
1731         if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false;  // 取得播放状态锁失败返回
1732 
1733     bool rm_is_index{ index == m_index };
1734     m_playlist.erase(m_playlist.begin() + index);
1735     if (index < m_index) --m_index;                         //如果要删除的曲目在正在播放的曲目之前,则正在播放的曲目序号减1
1736 
1737     AfterRemoveSong(rm_is_index);
1738 
1739     if (!skip_locking)
1740         GetPlayStatusMutex().unlock();
1741     return true;
1742 }
1743 
RemoveSongs(vector<int> indexes,bool skip_locking)1744 void CPlayer::RemoveSongs(vector<int> indexes, bool skip_locking)
1745 {
1746     if (IsPlaylistEmpty()) return;                          // 播放列表为空(或有一个占位SongInfo)返回
1747     // if (!m_playlist_mode) return;                           // 不是播放列表模式返回(文件夹模式可以“从磁盘删除”)
1748     if (m_loading) return;                                  // 播放列表载入中返回
1749     int list_size{ GetSongNum() };
1750     vector<int> indexes_;   // 存储检查过的未越界待移除index
1751     for (const auto& index : indexes)
1752         if (index >= 0 && index < list_size)
1753             indexes_.push_back(index);
1754     if (indexes_.empty()) return;                           // 没有有效的移除index返回
1755     if (!skip_locking)
1756         if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return;    // 取得播放状态锁失败返回
1757 
1758     std::sort(indexes_.rbegin(), indexes_.rend());      // 降序排序以免移除时需要修改索引值
1759     bool rm_is_index{ std::find(indexes_.begin(), indexes_.end(), m_index) != indexes_.end() };
1760     for (int rm_index : indexes_)
1761     {
1762         m_playlist.erase(m_playlist.begin() + rm_index);
1763         if (rm_index < m_index) --m_index;
1764     }
1765 
1766     AfterRemoveSong(rm_is_index);
1767 
1768     if (!skip_locking)
1769         GetPlayStatusMutex().unlock();
1770 }
1771 
RemoveSameSongs()1772 int CPlayer::RemoveSameSongs()
1773 {
1774     if (GetSongNum() < 2) return 0;                             // 播放列表为空或仅含有一个元素则返回
1775     if (m_playlist_mode != PM_PLAYLIST) return 0;               // 不是播放列表模式返回
1776     if (m_loading) return 0;                                    // 播放列表载入中返回
1777     if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return 0;  // 取得播放状态锁失败返回
1778 
1779     int removed = 0;
1780     for (int i = 0; i < GetSongNum(); i++)
1781     {
1782         for (int j = i + 1; j < GetSongNum(); j++)
1783         {
1784             if (m_playlist[i].IsSameSong(m_playlist[j]))
1785             {
1786                 if (j == m_index)
1787                     m_index = i;
1788                 else if (j > m_index)
1789                     --m_index;
1790                 m_playlist.erase(m_playlist.begin() + j);
1791                 ++removed;
1792                 --j;
1793             }
1794         }
1795     }
1796 
1797     if (removed)
1798         AfterRemoveSong(false); // 移除重复歌曲时m_index总是能够保持指向相同歌曲(虽然本身值可能改变)所以参数总为false
1799 
1800     GetPlayStatusMutex().unlock();
1801     return removed;
1802 }
1803 
RemoveInvalidSongs()1804 int CPlayer::RemoveInvalidSongs()
1805 {
1806     if (IsPlaylistEmpty()) return 0;                            // 播放列表为空或仅含有一个元素则返回
1807     if (m_playlist_mode != PM_PLAYLIST) return 0;               // 不是播放列表模式返回
1808     if (m_loading) return 0;                                    // 播放列表载入中返回
1809     if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return 0;  // 取得播放状态锁失败返回
1810 
1811     bool rm_is_index{};
1812     int removed = 0;
1813     for (int i = 0; i < GetSongNum(); i++)
1814     {
1815         if (!CCommon::FileExist(m_playlist[i].file_path) || m_playlist[i].length().isZero())
1816         {
1817             m_playlist.erase(m_playlist.begin() + i);
1818             if (i == m_index)
1819                 rm_is_index = true;
1820             removed++;
1821             i--;
1822         }
1823     }
1824 
1825     if (removed)
1826         AfterRemoveSong(rm_is_index);
1827 
1828     GetPlayStatusMutex().unlock();
1829     return removed;
1830 }
1831 
ClearPlaylist()1832 void CPlayer::ClearPlaylist()
1833 {
1834     if (IsPlaylistEmpty()) return;                          // 播放列表为空(或有一个占位SongInfo)返回
1835     if (m_playlist_mode != PM_PLAYLIST) return;             // 不是播放列表模式返回
1836     if (m_loading) return;                                  // 播放列表载入中返回
1837     if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return;  // 取得播放状态锁失败返回
1838 
1839     m_playlist.clear();
1840 
1841     AfterRemoveSong(true);
1842 
1843     GetPlayStatusMutex().unlock();
1844 }
1845 
MoveUp(int first,int last)1846 bool CPlayer::MoveUp(int first, int last)
1847 {
1848     if (m_loading)
1849         return false;
1850     if (m_playlist_mode != PM_PLAYLIST)
1851         return false;
1852 
1853     if (first <= 0 || last >= GetSongNum() || last < first)
1854         return false;
1855 
1856     if (m_index >= first && m_index <= last)
1857         m_index--;
1858     else if (m_index == first - 1)
1859         m_index = last;
1860 
1861     for (int i = first; i <= last; i++)
1862     {
1863         std::swap(m_playlist[i - 1], m_playlist[i]);
1864     }
1865     m_sort_mode = SM_UNSORT;        // 修改会失去排序状态
1866     OnPlaylistChange();
1867     SaveCurrentPlaylist();
1868     return true;
1869 }
1870 
MoveDown(int first,int last)1871 bool CPlayer::MoveDown(int first, int last)
1872 {
1873     if (m_loading)
1874         return false;
1875     if (m_playlist_mode != PM_PLAYLIST)
1876         return false;
1877 
1878     if (first < 0 || last >= GetSongNum() - 1 || last < first)
1879         return false;
1880 
1881     if (m_index >= first && m_index <= last)
1882         m_index++;
1883     else if (m_index == last + 1)
1884         m_index = first;
1885 
1886     for (int i = last + 1; i > first; i--)
1887     {
1888         std::swap(m_playlist[i], m_playlist[i - 1]);
1889     }
1890     m_sort_mode = SM_UNSORT;        // 修改会失去排序状态
1891     OnPlaylistChange();
1892     SaveCurrentPlaylist();
1893     return true;
1894 }
1895 
MoveItems(std::vector<int> indexes,int dest)1896 int CPlayer::MoveItems(std::vector<int> indexes, int dest)
1897 {
1898     if (m_loading)
1899         return -1;
1900     if (m_playlist_mode != PM_PLAYLIST)
1901         return -1;
1902 
1903     if (std::find(indexes.begin(), indexes.end(), dest) != indexes.end())
1904         return -1;
1905 
1906     std::wstring dest_file_path;        //保存目标位置的文件路径
1907     int dest_track = 0;                      //保存目标位置的音轨
1908     if (dest >= 0 && dest < GetSongNum())
1909     {
1910         dest_file_path = m_playlist[dest].file_path;
1911         dest_track = m_playlist[dest].track;
1912     }
1913 
1914     SongInfo current_file{ GetCurrentSongInfo() };
1915 
1916     //把要移动的项目取出并删除要移动的项目
1917     std::vector<SongInfo> moved_items;
1918     int size = indexes.size();
1919     for (int i{}; i < size; i++)
1920     {
1921         if (indexes[i] >= 0 && indexes[i] < GetSongNum())
1922         {
1923             moved_items.push_back(m_playlist[indexes[i]]);
1924             m_playlist.erase(m_playlist.begin() + indexes[i]);
1925             if (i <= size - 2 && indexes[i + 1] > indexes[i])
1926             {
1927                 for (int j{ i + 1 }; j < size; j++)
1928                     indexes[j]--;
1929             }
1930         }
1931     }
1932 
1933     //重新查找目标文件的位置
1934     int dest_index;
1935     auto iter_dest = std::find_if(m_playlist.begin(), m_playlist.end(), [&](const SongInfo& song)
1936         {
1937             return song.file_path == dest_file_path && song.track == dest_track;
1938         });
1939     if (dest >= 0 && iter_dest != m_playlist.end())
1940     {
1941         //把要移动的项目插入到目标位置
1942         dest_index = iter_dest - m_playlist.begin();
1943         m_playlist.insert(iter_dest, moved_items.begin(), moved_items.end());
1944     }
1945     else        //dest为负,则把要移动的项目插入到列表最后
1946     {
1947         dest_index = GetSongNum();
1948         for (const auto& song : moved_items)
1949         {
1950             m_playlist.push_back(song);
1951         }
1952     }
1953 
1954     //查找正在播放的曲目
1955     auto iter_play = std::find_if(m_playlist.begin(), m_playlist.end(), [&](const SongInfo& song)
1956         {
1957             return song.IsSameSong(current_file);
1958         });
1959     if (iter_play == m_playlist.end())
1960         m_index = 0;
1961     else
1962         m_index = iter_play - m_playlist.begin();
1963 
1964     m_sort_mode = SM_UNSORT;        // 修改会失去排序状态
1965     OnPlaylistChange();
1966     SaveCurrentPlaylist();
1967     return dest_index;
1968 }
1969 
SeekTo(int position)1970 void CPlayer::SeekTo(int position)
1971 {
1972     if (position > m_song_length.toInt())
1973         position = m_song_length.toInt();
1974     m_current_position.fromInt(position);
1975     if (m_playlist[m_index].is_cue)
1976     {
1977         position += m_playlist[m_index].start_pos.toInt();
1978     }
1979     m_pCore->SetCurPosition(position);
1980     GetPlayerCoreError(L"SetCurPosition");
1981 }
1982 
SeekTo(double position)1983 void CPlayer::SeekTo(double position)
1984 {
1985     int pos = static_cast<int>(m_song_length.toInt() * position);
1986     SeekTo(pos);
1987 }
1988 
1989 //void CPlayer::SeekTo(HSTREAM hStream, int position)
1990 //{
1991 //    double pos_sec = static_cast<double>(position) / 1000.0;
1992 //    QWORD pos_bytes;
1993 //    pos_bytes = BASS_ChannelSeconds2Bytes(hStream, pos_sec);
1994 //    BASS_ChannelSetPosition(hStream, pos_bytes, BASS_POS_BYTE);
1995 //    GetInstance().GetPlayerCoreError();
1996 //}
1997 
ClearLyric()1998 void CPlayer::ClearLyric()
1999 {
2000     m_Lyrics = CLyrics{};
2001     GetCurrentSongInfo2().lyric_file.clear();
2002     SongInfo song_info{ CSongDataManager::GetInstance().GetSongInfo3(GetCurrentSongInfo()) };
2003     song_info.lyric_file.clear();
2004     CSongDataManager::GetInstance().AddItem(song_info);
2005 }
2006 
GetTimeString() const2007 wstring CPlayer::GetTimeString() const
2008 {
2009     wchar_t buff[64];
2010     swprintf_s(buff, L"%d:%.2d/%d:%.2d", m_current_position.min, m_current_position.sec, m_song_length.min, m_song_length.sec);
2011     return wstring(buff);
2012 }
2013 
GetPlayingState() const2014 wstring CPlayer::GetPlayingState() const
2015 {
2016     static wstring str_paly_error = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_ERROR");
2017     static wstring str_stoped = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_STOPED");
2018     static wstring str_paused = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_PAUSED");
2019     static wstring str_playing = theApp.m_str_table.LoadText(L"UI_TXT_PLAYSTATUS_PLAYING");
2020     if (m_error_code != 0)
2021         return str_paly_error;
2022     switch (m_playing)
2023     {
2024     case PS_STOPED:
2025         return str_stoped;
2026     case PS_PAUSED:
2027         return str_paused;
2028     case PS_PLAYING:
2029         return str_playing;
2030     default:
2031         return wstring();
2032     }
2033 }
2034 
GetCurrentSongInfo() const2035 const SongInfo& CPlayer::GetCurrentSongInfo() const
2036 {
2037     if (m_index >= 0 && m_index < GetSongNum())
2038         return m_playlist[m_index];
2039     else return m_no_use;
2040 }
2041 
GetCurrentSongInfo2()2042 SongInfo& CPlayer::GetCurrentSongInfo2()
2043 {
2044     if (m_index >= 0 && m_index < GetSongNum())
2045         return m_playlist[m_index];
2046     else return m_no_use;
2047 }
2048 
GetNextTrack() const2049 SongInfo CPlayer::GetNextTrack() const
2050 {
2051     auto GetLegitSongInfo = [this](int x) { return x >= 0 && x < static_cast<int>(m_playlist.size()) ? m_playlist[x] : SongInfo(); };
2052     if (!m_next_tracks.empty())
2053     {
2054         return GetLegitSongInfo(m_next_tracks.front());
2055     }
2056     switch (m_repeat_mode)
2057     {
2058     case RM_PLAY_ORDER:
2059     {
2060         return GetLegitSongInfo(m_index + 1);
2061     }
2062 
2063     case RM_PLAY_SHUFFLE:
2064     {
2065         int shuffle_index = GetNextShuffleIdx();
2066         if (shuffle_index == 0 && m_is_shuffle_list_played || m_shuffle_list.empty())
2067         {
2068             //如果shuffle_index == 0且列表播放过,说明列表中的曲目已经无序播放完一遍,此时无序列表要重新生成,因此下一首曲目是不确定的
2069             //以及shuffle之前m_shuffle_list为空
2070             return SongInfo();
2071         }
2072         else
2073         {
2074             return GetLegitSongInfo(m_shuffle_list[shuffle_index]);
2075         }
2076     }
2077 
2078     case RM_PLAY_RANDOM:
2079         return SongInfo();
2080 
2081     case RM_LOOP_PLAYLIST:
2082     {
2083         int index = m_index + 1;
2084         if (index >= GetSongNum() || index < 0)
2085             index = 0;
2086         return m_playlist[index];
2087     }
2088 
2089     case RM_LOOP_TRACK:
2090         return GetCurrentSongInfo();
2091 
2092     case RM_PLAY_TRACK:
2093         return SongInfo();
2094 
2095     default:
2096         return SongInfo();
2097     }
2098 }
2099 
SetFavourite(int index,bool favourite)2100 void CPlayer::SetFavourite(int index, bool favourite)
2101 {
2102     if (IsError())
2103         return;
2104     if (index >= 0 && index < GetSongNum())
2105     {
2106         m_playlist[index].is_favourite = favourite;
2107     }
2108     if (theApp.m_media_lib_setting_data.enable_lastfm) {
2109         theApp.UpdateLastFMFavourite(favourite);
2110     }
2111 }
2112 
SetFavourite(bool favourite)2113 void CPlayer::SetFavourite(bool favourite)
2114 {
2115     SetFavourite(m_index, favourite);
2116 }
2117 
IsFavourite(int index)2118 bool CPlayer::IsFavourite(int index)
2119 {
2120     if (CRecentList::Instance().IsPlayingSpecPlaylist(CRecentList::PT_FAVOURITE))
2121         return true;
2122     if (index >= 0 && index < GetSongNum())
2123     {
2124         return m_playlist[index].is_favourite;
2125     }
2126     return false;
2127 }
2128 
IsFavourite()2129 bool CPlayer::IsFavourite()
2130 {
2131     return IsFavourite(m_index);
2132 }
2133 
AddListenTime(int sec)2134 void CPlayer::AddListenTime(int sec)
2135 {
2136     if (m_index >= 0 && m_index < GetSongNum())
2137     {
2138         m_playlist[m_index].listen_time += sec; // m_playlist的信息不会保存到媒体库,此处仅为排序维护
2139         SongInfo song_info{ CSongDataManager::GetInstance().GetSongInfo3(m_playlist[m_index]) };
2140         song_info.listen_time += sec;
2141         CSongDataManager::GetInstance().AddItem(song_info);
2142     }
2143     if (m_enable_lastfm) {
2144         int speed = static_cast<int>(m_speed * 1000);
2145         theApp.m_lastfm.AddCurrentPlayedTime(sec * speed);
2146         if (!theApp.m_lastfm.IsPushed()) {
2147             if (theApp.m_lastfm.CurrentTrackScrobbleable()) {
2148                 theApp.m_lastfm.PushCurrentTrackToCache();
2149             }
2150         }
2151         if (theApp.m_media_lib_setting_data.lastfm_auto_scrobble && theApp.m_lastfm.IsScrobbeable()) {
2152             theApp.LastFMScrobble();
2153         }
2154     }
2155 }
2156 
GetChannels()2157 int CPlayer::GetChannels()
2158 {
2159     return m_pCore == nullptr ? 0 : m_pCore->GetChannels();
2160 }
2161 
GetFreq()2162 int CPlayer::GetFreq()
2163 {
2164     return m_pCore == nullptr ? 0 : m_pCore->GetFReq();
2165 }
2166 
GetBassHandle() const2167 unsigned int CPlayer::GetBassHandle() const
2168 {
2169     if (IsBassCore())
2170     {
2171         CBassCore* bass_core = dynamic_cast<CBassCore*>(m_pCore);
2172         if (bass_core != nullptr)
2173         {
2174             return bass_core->GetHandle();
2175         }
2176     }
2177     return 0;
2178 }
2179 
ReIniPlayerCore(bool replay)2180 void CPlayer::ReIniPlayerCore(bool replay)
2181 {
2182     if (m_loading) return;
2183     if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(5000))) return;    // 这里多等一会,系统从挂起中恢复可能很卡
2184     int playing = m_playing;
2185     int current_position = GetCurrentPosition();
2186     MusicControl(Command::CLOSE);   // stop可以忽略但close中有不应忽略的保存歌词操作
2187     UnInitPlayerCore();
2188     IniPlayerCore();
2189     MusicControl(Command::OPEN);
2190     SeekTo(current_position);
2191     if (replay && playing == PS_PLAYING)
2192     {
2193         MusicControl(Command::PLAY);
2194     }
2195     else
2196     {
2197         m_playing = PS_STOPED;
2198     }
2199     GetPlayStatusMutex().unlock();
2200 }
2201 
SortPlaylist(bool is_init)2202 void CPlayer::SortPlaylist(bool is_init)
2203 {
2204     if (m_loading && !is_init) return;
2205     CWaitCursor wait_cursor;
2206     SongInfo current_song = GetCurrentSongInfo();
2207     ASSERT(m_sort_mode != SM_UNSORT);
2208     auto sort_fun = SongInfo::GetSortFunc(m_sort_mode == SM_UNSORT ? SM_U_FILE : m_sort_mode);
2209     std::stable_sort(m_playlist.begin(), m_playlist.end(), sort_fun);
2210 
2211     if (!is_init)   // 由初始化完成方法调用时不重新查找index
2212     {
2213         //播放列表排序后,查找正在播放项目的序号
2214         for (int i{}; i < GetSongNum(); i++)
2215         {
2216             if (current_song.IsSameSong(m_playlist[i]))
2217             {
2218                 m_index = i;
2219                 break;
2220             }
2221         }
2222     }
2223     OnPlaylistChange();
2224     SaveCurrentPlaylist();
2225 }
2226 
OnExit()2227 void CPlayer::OnExit()
2228 {
2229     SaveConfig();
2230     //退出时保存最后播放的曲目和位置
2231     SaveRecentInfoToFiles();
2232 }
2233 
SaveCurrentPlaylist()2234 void CPlayer::SaveCurrentPlaylist()
2235 {
2236     if (m_playlist_mode == PM_PLAYLIST)
2237         CPlaylistFile::SavePlaylistToFile(m_playlist, m_playlist_path);
2238 }
2239 
2240 //void CPlayer::SetFXHandle()
2241 //{
2242 //    GetPlayerCoreError();
2243 //}
2244 //
2245 //void CPlayer::RemoveFXHandle()
2246 //{
2247 //    GetPlayerCoreError();
2248 //}
2249 
ApplyEqualizer(int channel,int gain)2250 void CPlayer::ApplyEqualizer(int channel, int gain)
2251 {
2252     m_pCore->ApplyEqualizer(channel, gain);
2253     GetPlayerCoreError(L"ApplyEqualizer");
2254 }
2255 
SetEqualizer(int channel,int gain)2256 void CPlayer::SetEqualizer(int channel, int gain)
2257 {
2258     if (channel < 0 || channel >= EQU_CH_NUM) return;
2259     m_equalizer_gain[channel] = gain;
2260     ApplyEqualizer(channel, gain);
2261 }
2262 
GeEqualizer(int channel)2263 int CPlayer::GeEqualizer(int channel)
2264 {
2265     if (channel < 0 || channel >= EQU_CH_NUM) return 0;
2266     //BASS_DX8_PARAMEQ parameq;
2267     //int rtn;
2268     //rtn = BASS_FXGetParameters(m_equ_handle[channel], &parameq);
2269     //return static_cast<int>(parameq.fGain);
2270     return m_equalizer_gain[channel];
2271 }
2272 
SetAllEqualizer()2273 void CPlayer::SetAllEqualizer()
2274 {
2275     for (int i{}; i < EQU_CH_NUM; i++)
2276     {
2277         ApplyEqualizer(i, m_equalizer_gain[i]);
2278     }
2279 }
2280 
ClearAllEqulizer()2281 void CPlayer::ClearAllEqulizer()
2282 {
2283     for (int i{}; i < EQU_CH_NUM; i++)
2284     {
2285         ApplyEqualizer(i, 0);
2286     }
2287 }
2288 
EnableEqualizer(bool enable)2289 void CPlayer::EnableEqualizer(bool enable)
2290 {
2291     if (enable)
2292         SetAllEqualizer();
2293     else
2294         ClearAllEqulizer();
2295     m_equ_enable = enable;
2296 }
2297 
EnableReverb(bool enable)2298 void CPlayer::EnableReverb(bool enable)
2299 {
2300     if (enable)
2301     {
2302         if (m_reverb_mix < 0) m_reverb_mix = 0;
2303         if (m_reverb_mix > 100) m_reverb_mix = 100;
2304         if (m_reverb_time < 1) m_reverb_time = 1;
2305         if (m_reverb_time > 300) m_reverb_time = 300;
2306         m_pCore->SetReverb(m_reverb_mix, m_reverb_time);
2307         GetPlayerCoreError(L"SetReverb");
2308     }
2309     else
2310     {
2311         m_pCore->ClearReverb();
2312         GetPlayerCoreError(L"ClearReverb");
2313     }
2314     m_reverb_enable = enable;
2315 }
2316 
2317 
SetARepeatPoint()2318 bool CPlayer::SetARepeatPoint()
2319 {
2320     m_a_repeat = m_current_position;
2321     m_ab_repeat_mode = AM_A_SELECTED;
2322     return true;
2323 }
2324 
SetBRepeatPoint()2325 bool CPlayer::SetBRepeatPoint()
2326 {
2327     if (m_ab_repeat_mode != AM_NONE)
2328     {
2329         Time time_span = m_current_position - m_a_repeat;
2330         if (time_span > 200 && time_span < m_song_length)		//B点位置必须至少超过A点200毫秒
2331         {
2332             m_b_repeat = m_current_position;
2333             m_ab_repeat_mode = AM_AB_REPEAT;
2334             return true;
2335         }
2336     }
2337     return false;
2338 }
2339 
ContinueABRepeat()2340 bool CPlayer::ContinueABRepeat()
2341 {
2342     if (m_ab_repeat_mode == AM_AB_REPEAT)		//在AB重复状态下,将当前重复B点设置为下一次的重复A点
2343     {
2344         m_a_repeat = m_b_repeat;
2345         m_ab_repeat_mode = AM_A_SELECTED;
2346         if (GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000)))
2347         {
2348             SeekTo(m_a_repeat.toInt());
2349             GetPlayStatusMutex().unlock();
2350         }
2351         return true;
2352     }
2353     return false;
2354 }
2355 
DoABRepeat()2356 void CPlayer::DoABRepeat()
2357 {
2358     switch (m_ab_repeat_mode)
2359     {
2360     case CPlayer::AM_NONE:
2361         SetARepeatPoint();
2362         break;
2363     case CPlayer::AM_A_SELECTED:
2364         if (!SetBRepeatPoint())
2365             ResetABRepeat();
2366         break;
2367     case CPlayer::AM_AB_REPEAT:
2368         ResetABRepeat();
2369         break;
2370     default:
2371         break;
2372     }
2373 }
2374 
ResetABRepeat()2375 void CPlayer::ResetABRepeat()
2376 {
2377     m_ab_repeat_mode = AM_NONE;
2378 }
2379 
ConnotPlayWarning() const2380 void CPlayer::ConnotPlayWarning() const
2381 {
2382     if (m_pCore->IsMidiConnotPlay())
2383         PostMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_CONNOT_PLAY_WARNING, 0, 0);
2384 }
2385 
SearchAlbumCover()2386 void CPlayer::SearchAlbumCover()
2387 {
2388     CSingleLock sync(&m_album_cover_sync, TRUE);
2389     //static wstring last_file_path;
2390     //if (last_file_path != GetCurrentFilePath())		//防止同一个文件多次获取专辑封面
2391     //{
2392     m_album_cover.Destroy();
2393     SongInfo song_info{ CSongDataManager::GetInstance().GetSongInfo3(GetCurrentSongInfo()) };
2394     bool always_use_external_album_cover{ song_info.AlwaysUseExternalAlbumCover() };
2395     if ((!theApp.m_app_setting_data.use_out_image || theApp.m_app_setting_data.use_inner_image_first) && !IsOsuFile() && !always_use_external_album_cover)
2396     {
2397         //从文件获取专辑封面
2398         CAudioTag audio_tag(GetCurrentSongInfo2(), GetBassHandle());
2399         m_album_cover_path = audio_tag.GetAlbumCover(m_album_cover_type);
2400         if (!m_album_cover_path.empty())
2401         {
2402             m_album_cover.Load(m_album_cover_path.c_str());
2403             AlbumCoverResize();
2404             MediaTransControlsLoadThumbnail();
2405         }
2406     }
2407     m_inner_cover = !m_album_cover.IsNull();
2408 
2409     if (/*theApp.m_app_setting_data.use_out_image && */m_album_cover.IsNull())
2410     {
2411         //获取不到专辑封面时尝试使用外部图片作为封面
2412         SearchOutAlbumCover();
2413     }
2414     //AlbumCoverGaussBlur();
2415     //}
2416     //last_file_path = GetCurrentFilePath();
2417 
2418     ////如果专辑封面过大,则将其缩小,以提高性能
2419     //if (!m_album_cover.IsNull() && (m_album_cover.GetWidth() > 800 || m_album_cover.GetHeight() > 800))
2420     //{
2421     //    CSize image_size(m_album_cover.GetWidth(), m_album_cover.GetHeight());
2422     //    CCommon::SizeZoom(image_size, 800);
2423 
2424     //    CImage img_temp;
2425     //    if (CDrawCommon::BitmapStretch(&m_album_cover, &img_temp, image_size))
2426     //    {
2427     //        m_album_cover = img_temp;
2428     //    }
2429     //}
2430 }
2431 
AlbumCoverGaussBlur()2432 void CPlayer::AlbumCoverGaussBlur()
2433 {
2434     if (!theApp.m_app_setting_data.background_gauss_blur || !theApp.m_app_setting_data.enable_background)
2435         return;
2436     CSingleLock sync(&m_album_cover_sync, TRUE);
2437     if (m_album_cover.IsNull())
2438     {
2439         m_album_cover_blur.Destroy();
2440     }
2441     else
2442     {
2443         CImage image_tmp;
2444         CSize image_size(m_album_cover.GetWidth(), m_album_cover.GetHeight());
2445         //将图片缩小以减小高斯模糊的计算量
2446         CCommon::SizeZoom(image_size, 300);		//图片大小按比例缩放,使长边等于300
2447         CDrawCommon::ImageResize(m_album_cover, image_tmp, image_size);		//拉伸图片
2448 #ifdef _DEBUG
2449         image_tmp.Save(_T("..\\Debug\\image_tmp.bmp"), Gdiplus::ImageFormatBMP);
2450 #endif // _DEBUG
2451 
2452         //执行高斯模糊
2453         CGaussBlur gauss_blur;
2454         gauss_blur.SetSigma(static_cast<double>(theApp.m_app_setting_data.gauss_blur_radius) / 10);		//设置高斯模糊半径
2455         gauss_blur.DoGaussBlur(image_tmp, m_album_cover_blur);
2456     }
2457 }
2458 
AlbumCoverResize()2459 void CPlayer::AlbumCoverResize()
2460 {
2461     m_album_cover_info.GetInfo(m_album_cover);
2462     m_album_cover_info.size_exceed = false;
2463     if (!m_album_cover.IsNull() && theApp.m_nc_setting_data.max_album_cover_size > 0)
2464     {
2465         CSize image_size;
2466         image_size.cx = m_album_cover.GetWidth();
2467         image_size.cy = m_album_cover.GetHeight();
2468         if (max(image_size.cx, image_size.cy) > theApp.m_nc_setting_data.max_album_cover_size)      //如果专辑封面的尺寸大于设定的最大值,则将其缩小
2469         {
2470             wstring temp_img_path{ CCommon::GetTemplatePath() + ALBUM_COVER_TEMP_NAME };
2471             //缩小图片大小并保存到临时目录
2472             CDrawCommon::ImageResize(m_album_cover, temp_img_path, theApp.m_nc_setting_data.max_album_cover_size, IT_PNG);
2473             m_album_cover.Destroy();
2474             m_album_cover.Load(temp_img_path.c_str());
2475             m_album_cover_info.size_exceed = true;
2476         }
2477     }
2478 }
2479 
InitShuffleList(int first_song)2480 void CPlayer::InitShuffleList(int first_song)
2481 {
2482     if (first_song < 0 && first_song != -1 || first_song > static_cast<int>(m_shuffle_list.size()) - 1)
2483     {
2484         first_song = 0;
2485     }
2486     m_shuffle_list.resize(m_playlist.size());
2487     //为无序播放列表生成[0, n)的序号
2488     for (size_t i{}; i < m_shuffle_list.size(); i++)
2489         m_shuffle_list[i] = i;
2490 
2491     //将生成的序号打乱
2492     if (m_shuffle_list.size() > 1)
2493     {
2494         // 创建随机数引擎
2495         std::random_device rd;
2496         std::mt19937 generator(rd());
2497         if (first_song != -1)  // 指定第一首
2498         {
2499             if (first_song != 0)
2500             {
2501                 //交换
2502                 m_shuffle_list[first_song] = 0;
2503                 m_shuffle_list[0] = first_song;
2504             }
2505             std::shuffle(m_shuffle_list.begin() + 1, m_shuffle_list.end(), generator);
2506         }
2507         else
2508         {
2509             std::shuffle(m_shuffle_list.begin(), m_shuffle_list.end(), generator);
2510         }
2511     }
2512     m_shuffle_index = 0;
2513     m_is_shuffle_list_played = false;
2514 }
2515 
SearchOutAlbumCover()2516 void CPlayer::SearchOutAlbumCover()
2517 {
2518     CMusicPlayerCmdHelper helper;
2519     m_album_cover_path = helper.SearchAlbumCover(GetCurrentSongInfo());
2520     if (!m_album_cover.IsNull())
2521         m_album_cover.Destroy();
2522     m_album_cover.Load(m_album_cover_path.c_str());
2523     AlbumCoverResize();
2524     MediaTransControlsLoadThumbnail();
2525 }
2526 
IsOsuFile() const2527 bool CPlayer::IsOsuFile() const
2528 {
2529     return m_is_osu;
2530 }
2531 
IsPlaylistMode() const2532 bool CPlayer::IsPlaylistMode() const
2533 {
2534     return m_playlist_mode == PM_PLAYLIST;
2535 }
2536 
IsFolderMode() const2537 bool CPlayer::IsFolderMode() const
2538 {
2539     return m_playlist_mode == PM_FOLDER;
2540 }
2541 
IsMediaLibMode() const2542 bool CPlayer::IsMediaLibMode() const
2543 {
2544     return m_playlist_mode == PM_MEDIA_LIB;
2545 }
2546 
GetMediaLibPlaylistType() const2547 CMediaClassifier::ClassificationType CPlayer::GetMediaLibPlaylistType() const
2548 {
2549     return m_media_lib_playlist_type;
2550 }
2551 
IsPlaylistEmpty() const2552 bool CPlayer::IsPlaylistEmpty() const
2553 {
2554     return m_playlist.empty() || (m_playlist.size() == 1 /*&& m_playlist[0].file_name.empty()*/ && m_playlist[0].file_path.empty());
2555 }
2556 
SetPlaylistPath(const wstring & playlist_path)2557 void CPlayer::SetPlaylistPath(const wstring& playlist_path)
2558 {
2559     m_playlist_path = playlist_path;
2560 }
2561 
GetPlaylistPath() const2562 wstring CPlayer::GetPlaylistPath() const
2563 {
2564     return m_playlist_path;
2565 }
2566 
IsMciCore() const2567 bool CPlayer::IsMciCore() const
2568 {
2569     return m_pCore ? m_pCore->GetCoreType() == PT_MCI : false;
2570 }
2571 
IsBassCore() const2572 bool CPlayer::IsBassCore() const
2573 {
2574     return m_pCore ? m_pCore->GetCoreType() == PT_BASS : false;
2575 }
2576 
IsFfmpegCore() const2577 bool CPlayer::IsFfmpegCore() const {
2578     return m_pCore ? m_pCore->GetCoreType() == PT_FFMPEG : false;
2579 }
2580 
MediaTransControlsLoadThumbnail()2581 void CPlayer::MediaTransControlsLoadThumbnail()
2582 {
2583     if (CCommon::FileExist(m_album_cover_path))
2584     {
2585         if (CCommon::IsFileHidden(m_album_cover_path))
2586         {
2587             //如果专辑封面图片文件已隐藏,先将文件复制到Temp目录,再取消隐藏属性
2588             wstring temp_img_path{ CCommon::GetTemplatePath() + ALBUM_COVER_TEMP_NAME2 };
2589             CopyFile(m_album_cover_path.c_str(), temp_img_path.c_str(), FALSE);
2590             CCommon::SetFileHidden(temp_img_path, false);
2591             m_controls.loadThumbnail(temp_img_path);
2592         }
2593         else
2594         {
2595             //专辑封面图片文件未隐藏
2596             m_controls.loadThumbnail(m_album_cover_path);
2597         }
2598     }
2599     else
2600     {
2601         MediaTransControlsLoadThumbnailDefaultImage();
2602     }
2603 }
2604 
MediaTransControlsLoadThumbnailDefaultImage()2605 void CPlayer::MediaTransControlsLoadThumbnailDefaultImage()
2606 {
2607     if (m_album_cover.IsNull())
2608     {
2609         if (IsPlaying())
2610             m_controls.loadThumbnail((const BYTE*)theApp.m_image_set.default_cover_img_data.data(), theApp.m_image_set.default_cover_img_data.size());
2611         else
2612             m_controls.loadThumbnail((const BYTE*)theApp.m_image_set.default_cover_not_played_img_data.data(), theApp.m_image_set.default_cover_not_played_img_data.size());
2613     }
2614 }
2615 
UpdateLastFMCurrentTrack(const SongInfo & info)2616 void CPlayer::UpdateLastFMCurrentTrack(const SongInfo& info) {
2617     LastFMTrack track;
2618     track.ReadDataFrom(info);
2619     auto& current = theApp.m_lastfm.CurrentTrack();
2620     if (track == current) {
2621         int duration = track.duration.toInt() / 1000 * 9 / 10;
2622         if (track.timestamp - current.timestamp < duration) return;
2623     }
2624     theApp.m_lastfm.UpdateCurrentTrack(track);
2625     if (theApp.m_media_lib_setting_data.lastfm_enable_nowplaying) {
2626         theApp.UpdateLastFMNowPlaying();
2627     }
2628 }
2629