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], ¶meq);
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