1 #include "stdafx.h"
2 #include "BassCore.h"
3 #include "Common.h"
4 #include "AudioCommon.h"
5 #include "MusicPlayer2.h"
6 #include "Player.h"
7 #include "CommonDialogMgr.h"
8
9 CBASSMidiLibrary CBassCore::m_bass_midi_lib;
10 CBassCore::MidiLyricInfo CBassCore::m_midi_lyric;
11 BASS_MIDI_FONT CBassCore::m_sfont{};
12 CCriticalSection CBassCore::m_critical;
13 CBASSEncodeLibrary CBassCore::m_bass_encode_lib;
14 CBASSWmaLibrary CBassCore::m_bass_wma_lib;
15 CBassMixLibrary CBassCore::m_bass_mix_lib;
16 bool CBassCore::m_fading = false;
17
18 #define CONVERTING_TEMP_FILE_NAME L"converting_5k2019u6271iyt8j"
19
CBassCore()20 CBassCore::CBassCore()
21 {
22 }
23
24
~CBassCore()25 CBassCore::~CBassCore()
26 {
27 }
28
InitCore()29 void CBassCore::InitCore()
30 {
31 CSingleLock sync(&m_critical, TRUE);
32 //获取当前的音频输出设备
33 BASS_DEVICEINFO device_info;
34 int rtn;
35 int device_index{ 1 };
36 theApp.m_output_devices.clear();
37 DeviceInfo device{};
38 device.index = -1;
39 device.name = theApp.m_str_table.LoadText(L"TXT_OPT_PLAY_DEVICE_NAME_BASS_DEFAULT");
40 theApp.m_output_devices.push_back(device);
41 while (true)
42 {
43 device = DeviceInfo{};
44 rtn = BASS_GetDeviceInfo(device_index, &device_info);
45 if (rtn == 0)
46 break;
47 device.index = device_index;
48 if (device_info.name != nullptr)
49 device.name = CCommon::StrToUnicode(string(device_info.name));
50 if (device_info.driver != nullptr)
51 device.driver = CCommon::StrToUnicode(string(device_info.driver));
52 device.flags = device_info.flags;
53 theApp.m_output_devices.push_back(device);
54 device_index++;
55 }
56
57 theApp.m_play_setting_data.device_selected = 0;
58 for (size_t i{}; i < theApp.m_output_devices.size(); i++)
59 {
60 if (theApp.m_output_devices[i].name == theApp.m_play_setting_data.output_device)
61 {
62 theApp.m_play_setting_data.device_selected = i;
63 break;
64 }
65 }
66
67 //初始化BASE音频库
68 BASS_Init(
69 theApp.m_output_devices[theApp.m_play_setting_data.device_selected].index, //播放设备
70 44100,//输出采样率44100(常用值)
71 BASS_DEVICE_CPSPEAKERS,//信号,BASS_DEVICE_CPSPEAKERS 注释原文如下:
72 /* Use the Windows control panel setting to detect the number of speakers.*/
73 /* Soundcards generally have their own control panel to set the speaker config,*/
74 /* so the Windows control panel setting may not be accurate unless it matches that.*/
75 /* This flag has no effect on Vista, as the speakers are already accurately detected.*/
76 theApp.m_pMainWnd->m_hWnd,//程序窗口,0用于控制台程序
77 NULL//类标识符,0使用默认值
78 );
79
80 //向支持的文件列表插入原生支持的文件格式
81 CAudioCommon::m_surpported_format.clear();
82 SupportedFormat format;
83 format.description = theApp.m_str_table.LoadText(L"TXT_FILE_TYPE_BASE");
84 format.extensions.insert(format.extensions.end(), theApp.m_nc_setting_data.default_file_type.begin(), theApp.m_nc_setting_data.default_file_type.end());
85 for (const auto& f : theApp.m_nc_setting_data.default_file_type)
86 {
87 format.extensions_list += L"*.";
88 format.extensions_list += f;
89 format.extensions_list += L';';
90 }
91 if (!format.extensions_list.empty())
92 format.extensions_list.pop_back();
93
94 //format.extensions_list = L"*.mp3;*.wma;*.wav;*.flac;*.ogg;*.oga;*.m4a;*.mp4;*.cue;*.mp2;*.mp1;*.aif;*.aiff";
95 CAudioCommon::m_surpported_format.push_back(format);
96 CAudioCommon::m_all_surpported_extensions = format.extensions;
97 //载入BASS插件
98 wstring plugin_dir;
99 plugin_dir = theApp.m_local_dir + L"Plugins\\";
100 vector<wstring> plugin_files;
101 CCommon::GetFiles(plugin_dir + L"*.dll", plugin_files); //获取Plugins目录下所有的dll文件的文件名
102 m_plugin_handles.clear();
103 for (const auto& plugin_file : plugin_files)
104 {
105 //加载插件
106 HPLUGIN handle = BASS_PluginLoad((plugin_dir + plugin_file).c_str(), 0);
107 m_plugin_handles.push_back(handle);
108 //获取插件支持的音频文件类型
109 const BASS_PLUGININFO* plugin_info = BASS_PluginGetInfo(handle);
110 if (plugin_info == nullptr)
111 continue;
112 format.file_name = plugin_file;
113 format.description = CCommon::ASCIIToUnicode(plugin_info->formats->name); //插件支持文件类型的描述
114 format.extensions_list = CCommon::ASCIIToUnicode(plugin_info->formats->exts); //插件支持文件扩展名列表
115 //解析扩展名列表到vector
116 format.extensions.clear();
117 size_t index = 0, last_index = 0;
118 while (true)
119 {
120 index = format.extensions_list.find(L"*.", index + 1);
121 wstring ext{ format.extensions_list.substr(last_index + 2, index - last_index - 2) };
122 if (!ext.empty() && ext.back() == L';')
123 ext.pop_back();
124 format.extensions.push_back(ext);
125 if (!CCommon::IsItemInVector(CAudioCommon::m_all_surpported_extensions, ext))
126 CAudioCommon::m_all_surpported_extensions.push_back(ext);
127 if (index == wstring::npos)
128 break;
129 last_index = index;
130 }
131 CAudioCommon::m_surpported_format.push_back(format);
132
133 //载入MIDI音色库,用于播放MIDI
134 if (format.description == L"MIDI")
135 {
136 m_bass_midi_lib.Init(plugin_dir + plugin_file);
137 m_sfont_name = theApp.m_str_table.LoadText(L"UI_TXT_SF2_NAME_NONE");
138 m_sfont.font = 0;
139 if (m_bass_midi_lib.IsSucceed())
140 {
141 wstring sf2_path = theApp.m_play_setting_data.sf2_path;
142 if (!CCommon::FileExist(sf2_path)) //如果设置的音色库路径不存在,则从.\Plugins\soundfont\目录下查找音色库文件
143 {
144 vector<wstring> sf2s;
145 CCommon::GetFiles(plugin_dir + L"soundfont\\*.sf2", sf2s);
146 if (!sf2s.empty())
147 sf2_path = plugin_dir + L"soundfont\\" + sf2s[0];
148 }
149 if (CCommon::FileExist(sf2_path))
150 {
151 m_sfont.font = m_bass_midi_lib.BASS_MIDI_FontInit(sf2_path.c_str(), BASS_UNICODE);
152 if (m_sfont.font == 0)
153 {
154 wstring info = theApp.m_str_table.LoadTextFormat(L"LOG_SF2_LOAD_FAILED", { sf2_path });
155 theApp.WriteLog(info);
156 m_sfont_name = theApp.m_str_table.LoadText(L"UI_TXT_SF2_NAME_FAILDE");
157 }
158 else
159 {
160 //获取音色库信息
161 BASS_MIDI_FONTINFO sfount_info;
162 m_bass_midi_lib.BASS_MIDI_FontGetInfo(m_sfont.font, &sfount_info);
163 m_sfont_name = CCommon::StrToUnicode(sfount_info.name);
164 }
165 m_sfont.preset = -1;
166 m_sfont.bank = 0;
167 }
168 }
169 }
170 }
171 }
172
UnInitCore()173 void CBassCore::UnInitCore()
174 {
175 CSingleLock sync(&m_critical, TRUE);
176 BASS_Stop(); //停止输出
177 BASS_Free(); //释放Bass资源
178 if (m_bass_midi_lib.IsSucceed() && m_sfont.font != 0)
179 m_bass_midi_lib.BASS_MIDI_FontFree(m_sfont.font);
180 m_bass_midi_lib.UnInit();
181 for (const auto& handle : m_plugin_handles) //释放插件句柄
182 {
183 BASS_PluginFree(handle);
184 }
185 m_fading = false;
186 }
187
GetHandle()188 unsigned int CBassCore::GetHandle()
189 {
190 return m_musicStream;
191 }
192
GetAudioType()193 std::wstring CBassCore::GetAudioType()
194 {
195 return CAudioCommon::GetBASSChannelDescription(m_channel_info.ctype);
196 }
197
MidiLyricSync(HSYNC handle,DWORD channel,DWORD data,void * user)198 void CBassCore::MidiLyricSync(HSYNC handle, DWORD channel, DWORD data, void * user)
199 {
200 if (!m_bass_midi_lib.IsSucceed())
201 return;
202 m_midi_lyric.midi_no_lyric = false;
203 BASS_MIDI_MARK mark;
204 m_bass_midi_lib.BASS_MIDI_StreamGetMark(channel, (DWORD)user, data, &mark); // get the lyric/text
205 if (mark.text[0] == '@') return; // skip info
206 if (mark.text[0] == '\\')
207 {
208 // clear display
209 m_midi_lyric.midi_lyric.clear();
210 }
211 else if (mark.text[0] == '/')
212 {
213 m_midi_lyric.midi_lyric += L"\r\n";
214 const char* text = mark.text + 1;
215 m_midi_lyric.midi_lyric += CCommon::StrToUnicode(text, CodeType::ANSI);
216 }
217 else
218 {
219 m_midi_lyric.midi_lyric += CCommon::StrToUnicode(mark.text, CodeType::ANSI);
220 }
221 }
222
MidiEndSync(HSYNC handle,DWORD channel,DWORD data,void * user)223 void CBassCore::MidiEndSync(HSYNC handle, DWORD channel, DWORD data, void * user)
224 {
225 m_midi_lyric.midi_lyric.clear();
226 }
227
GetMidiPosition()228 void CBassCore::GetMidiPosition()
229 {
230 CSingleLock sync(&m_critical, TRUE);
231 if (m_is_midi)
232 {
233 //获取midi音乐的进度并转换成节拍数。(其中+ (m_midi_info.ppqn / 4)的目的是修正显示的节拍不准确的问题)
234 m_midi_info.midi_position = static_cast<int>((BASS_ChannelGetPosition(m_musicStream, BASS_POS_MIDI_TICK) + (m_midi_info.ppqn / 4)) / m_midi_info.ppqn);
235 }
236 }
237
SetFXHandle()238 void CBassCore::SetFXHandle()
239 {
240 if (m_musicStream == 0) return;
241 //if (!m_equ_enable) return;
242 //设置每个均衡器通道的句柄
243 for (int i{}; i < EQU_CH_NUM; i++)
244 {
245 m_equ_handle[i] = BASS_ChannelSetFX(m_musicStream, BASS_FX_DX8_PARAMEQ, 1);
246 }
247 //设置混响的句柄
248 m_reverb_handle = BASS_ChannelSetFX(m_musicStream, BASS_FX_DX8_REVERB, 1);
249 }
250
RemoveFXHandle()251 void CBassCore::RemoveFXHandle()
252 {
253 if (m_musicStream == 0) return;
254 //移除每个均衡器通道的句柄
255 for (int i{}; i < EQU_CH_NUM; i++)
256 {
257 if (m_equ_handle[i] != 0)
258 {
259 BASS_ChannelRemoveFX(m_musicStream, m_equ_handle[i]);
260 m_equ_handle[i] = 0;
261 }
262 }
263 //移除混响的句柄
264 if (m_reverb_handle != 0)
265 {
266 BASS_ChannelRemoveFX(m_musicStream, m_reverb_handle);
267 m_reverb_handle = 0;
268 }
269 }
270
GetBASSAudioInfo(HSTREAM hStream,SongInfo & song_info,int flag)271 void CBassCore::GetBASSAudioInfo(HSTREAM hStream, SongInfo & song_info, int flag)
272 {
273 //获取长度
274 if (flag&AF_LENGTH)
275 song_info.end_pos = CBassCore::GetBASSSongLength(hStream);
276 //获取比特率
277 if(flag&AF_BITRATE)
278 {
279 float bitrate{};
280 BASS_ChannelGetAttribute(hStream, BASS_ATTRIB_BITRATE, &bitrate);
281 song_info.bitrate = static_cast<int>(bitrate + 0.5f);
282 }
283 //获取采样频率、通道数、位深度
284 if (flag & AF_CHANNEL_INFO)
285 {
286 BASS_CHANNELINFO info{};
287 BASS_ChannelGetInfo(hStream, &info);
288 song_info.freq = info.freq;
289 song_info.bits = static_cast<BYTE>(info.origres);
290 song_info.channels = static_cast<BYTE>(info.chans);
291 }
292 if(flag&AF_TAG_INFO)
293 {
294 CAudioTag audio_tag(song_info, hStream);
295 audio_tag.GetAudioTag();
296 audio_tag.GetAudioRating();
297 //获取midi音乐的标题
298 if (CBassCore::m_bass_midi_lib.IsSucceed() && audio_tag.GetAudioType() == AU_MIDI)
299 {
300 BASS_MIDI_MARK mark;
301 if (CBassCore::m_bass_midi_lib.BASS_MIDI_StreamGetMark(hStream, BASS_MIDI_MARK_TRACK, 0, &mark) && !mark.track)
302 {
303 song_info.title = CCommon::StrToUnicode(mark.text);
304 }
305 }
306 }
307 }
308
GetChannels()309 int CBassCore::GetChannels()
310 {
311 return m_channel_info.chans;
312 }
313
GetFReq()314 int CBassCore::GetFReq()
315 {
316 return m_channel_info.freq;
317 }
318
GetSoundFontName()319 wstring CBassCore::GetSoundFontName()
320 {
321 return m_sfont_name;
322 }
323
Open(const wchar_t * file_path)324 void CBassCore::Open(const wchar_t * file_path)
325 {
326 CSingleLock sync(&m_critical, TRUE);
327
328 m_last_playing_state = PLAYING_STATE_DEFAULT_VALUE;
329 if (m_musicStream != 0) //打开前如果音频句柄没有关闭,先将其关闭,确保同时只能打开一个音频文件
330 Close();
331
332 m_file_path = file_path;
333 if (CCommon::IsURL(m_file_path))
334 m_musicStream = BASS_StreamCreateURL(file_path, 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE, NULL, NULL);
335 else
336 m_musicStream = BASS_StreamCreateFile(FALSE, /*(GetCurrentFilePath()).c_str()*/file_path, 0, 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE);
337 BASS_ChannelGetInfo(m_musicStream, &m_channel_info);
338 m_is_midi = (CAudioCommon::GetAudioTypeByBassChannel(m_channel_info.ctype) == AudioType::AU_MIDI);
339 if (m_bass_midi_lib.IsSucceed() && m_is_midi && m_sfont.font != 0)
340 m_bass_midi_lib.BASS_MIDI_StreamSetFonts(m_musicStream, &m_sfont, 1);
341
342 //如果文件是MIDI音乐,则打开时获取MIDI音乐的信息
343 if (m_is_midi && m_bass_midi_lib.IsSucceed())
344 {
345 //获取MIDI音乐信息
346 BASS_ChannelGetAttribute(m_musicStream, BASS_ATTRIB_MIDI_PPQN, &m_midi_info.ppqn); // get PPQN value
347 m_midi_info.midi_length = static_cast<int>(BASS_ChannelGetLength(m_musicStream, BASS_POS_MIDI_TICK) / m_midi_info.ppqn);
348 m_midi_info.tempo = m_bass_midi_lib.BASS_MIDI_StreamGetEvent(m_musicStream, 0, MIDI_EVENT_TEMPO);
349 m_midi_info.speed = 60000000 / m_midi_info.tempo;
350 //获取MIDI音乐内嵌歌词
351 BASS_MIDI_MARK mark;
352 m_midi_lyric.midi_lyric.clear();
353 if (m_bass_midi_lib.BASS_MIDI_StreamGetMark(m_musicStream, BASS_MIDI_MARK_LYRIC, 0, &mark)) // got lyrics
354 BASS_ChannelSetSync(m_musicStream, BASS_SYNC_MIDI_MARK, BASS_MIDI_MARK_LYRIC, MidiLyricSync, (void*)BASS_MIDI_MARK_LYRIC);
355 else if (m_bass_midi_lib.BASS_MIDI_StreamGetMark(m_musicStream, BASS_MIDI_MARK_TEXT, 20, &mark)) // got text instead (over 20 of them)
356 BASS_ChannelSetSync(m_musicStream, BASS_SYNC_MIDI_MARK, BASS_MIDI_MARK_TEXT, MidiLyricSync, (void*)BASS_MIDI_MARK_TEXT);
357 BASS_ChannelSetSync(m_musicStream, BASS_SYNC_END, 0, MidiEndSync, 0);
358 m_midi_lyric.midi_no_lyric = true;
359 }
360 SetFXHandle();
361 m_musicStream = BASS_FX_TempoCreate(m_musicStream, BASS_FX_FREESOURCE);
362 }
363
Close()364 void CBassCore::Close()
365 {
366 CSingleLock sync(&m_critical, TRUE);
367 if (m_musicStream != 0)
368 {
369 if (KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID))
370 BASS_ChannelStop(m_musicStream);
371 RemoveFXHandle();
372 BASS_StreamFree(m_musicStream);
373 m_musicStream = 0;
374 }
375 }
376
Play()377 void CBassCore::Play()
378 {
379 m_playing_state = PS_PLAYING;
380 if (theApp.m_play_setting_data.fade_effect && theApp.m_play_setting_data.fade_time > 0) //如果设置了播放时音量淡入淡出
381 {
382 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID);
383 int pos = GetCurPosition();
384 pos -= (theApp.m_play_setting_data.fade_time / 2);
385 if (pos < 0)
386 pos = 0;
387 SetCurPosition(pos);
388 BASS_ChannelSetAttribute(m_musicStream, BASS_ATTRIB_VOL, 0); //先将音量设为0
389 BASS_ChannelPlay(m_musicStream, FALSE);
390 float volume = static_cast<float>(m_volume) / 100;
391 BASS_ChannelSlideAttribute(m_musicStream, BASS_ATTRIB_VOL, volume, theApp.m_play_setting_data.fade_time); //音量渐变到原来的音量
392 }
393 else
394 {
395 BASS_ChannelPlay(m_musicStream, FALSE);
396 }
397 }
398
Pause()399 void CBassCore::Pause()
400 {
401 m_playing_state = PS_PAUSED;
402 if (theApp.m_play_setting_data.fade_effect && theApp.m_play_setting_data.fade_time > 0) //如果设置了播放时音量淡入淡出
403 {
404 BASS_ChannelSlideAttribute(m_musicStream, BASS_ATTRIB_VOL, 0, theApp.m_play_setting_data.fade_time); //音量渐变到0
405 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID);
406 m_fading = true;
407 //设置一个淡出时间的定时器
408 SetTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID, theApp.m_play_setting_data.fade_time, [](HWND Arg1, UINT Arg2, UINT_PTR Arg3, DWORD Arg4)
409 {
410 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID);
411 BASS_ChannelPause(CPlayer::GetInstance().GetBassHandle()); //当定时器器触发时,即音量已经渐变到0,执行暂停操作
412 m_fading = false;
413 });
414 }
415 else
416 {
417 BASS_ChannelPause(m_musicStream);
418 }
419 }
420
Stop()421 void CBassCore::Stop()
422 {
423 m_playing_state = PS_STOPED;
424 DWORD playing_state = BASS_ChannelIsActive(m_musicStream);
425 if (theApp.m_play_setting_data.fade_effect && theApp.m_play_setting_data.fade_time > 0 && playing_state == BASS_ACTIVE_PLAYING)
426 {
427 BASS_ChannelSlideAttribute(m_musicStream, BASS_ATTRIB_VOL, 0, theApp.m_play_setting_data.fade_time);
428 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID);
429 m_fading = true;
430 SetTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID, theApp.m_play_setting_data.fade_time, [](HWND Arg1, UINT Arg2, UINT_PTR Arg3, DWORD Arg4)
431 {
432 KillTimer(theApp.m_pMainWnd->GetSafeHwnd(), FADE_TIMER_ID);
433 BASS_ChannelStop(CPlayer::GetInstance().GetBassHandle());
434 BASS_ChannelSetPosition(CPlayer::GetInstance().GetBassHandle(), 0, BASS_POS_BYTE);
435 m_fading = false;
436 });
437 }
438 else
439 {
440 BASS_ChannelStop(m_musicStream);
441 SetCurPosition(0);
442 }
443 }
444
SetVolume(int vol)445 void CBassCore::SetVolume(int vol)
446 {
447 if (!m_fading)
448 {
449 m_volume = vol;
450 float volume = static_cast<float>(vol) / 100.0f;
451 BASS_ChannelSetAttribute(m_musicStream, BASS_ATTRIB_VOL, volume);
452 }
453 }
454
SetSpeed(float speed)455 void CBassCore::SetSpeed(float speed)
456 {
457 if (std::fabs(speed) < 0.01 || std::fabs(speed - 1) < 0.01 || speed < MIN_PLAY_SPEED || speed > MAX_PLAY_SPEED)
458 speed = 1;
459 float tempo = (speed - 1) * 100;
460 BASS_ChannelSetAttribute(m_musicStream, BASS_ATTRIB_TEMPO, tempo);
461 }
462
SetPitch(int pitch)463 void CBassCore::SetPitch(int pitch)
464 {
465 if (pitch < MIN_PLAY_PITCH || pitch > MAX_PLAY_PITCH)
466 {
467 pitch = 0;
468 }
469 BASS_ChannelSetAttribute(m_musicStream, BASS_ATTRIB_TEMPO_PITCH, pitch);
470 }
471
SongIsOver()472 bool CBassCore::SongIsOver()
473 {
474 DWORD state = BASS_ChannelIsActive(m_musicStream);
475 bool is_over{ (m_last_playing_state == BASS_ACTIVE_PLAYING && state == BASS_ACTIVE_STOPPED)
476 || m_error_code == BASS_ERROR_ENDED };
477 m_last_playing_state = state;
478 return is_over && m_playing_state == PS_PLAYING && m_musicStream != 0;
479 }
480
GetCurPosition()481 int CBassCore::GetCurPosition()
482 {
483 CSingleLock sync(&m_critical, TRUE);
484 if (m_musicStream == 0)
485 return 0;
486 QWORD pos_bytes;
487 pos_bytes = BASS_ChannelGetPosition(m_musicStream, BASS_POS_BYTE);
488 double pos_sec;
489 pos_sec = BASS_ChannelBytes2Seconds(m_musicStream, pos_bytes);
490 int current_position = static_cast<int>(pos_sec * 1000);
491 if (current_position == -1000) current_position = 0;
492
493 GetMidiPosition();
494 return current_position;
495 }
496
GetSongLength()497 int CBassCore::GetSongLength()
498 {
499 CSingleLock sync(&m_critical, TRUE);
500 QWORD lenght_bytes;
501 lenght_bytes = BASS_ChannelGetLength(m_musicStream, BASS_POS_BYTE);
502 double length_sec;
503 length_sec = BASS_ChannelBytes2Seconds(m_musicStream, lenght_bytes);
504 int song_length = static_cast<int>(length_sec * 1000);
505 if (song_length <= -1000) song_length = 0;
506 return song_length;
507 }
508
SetCurPosition(int position)509 void CBassCore::SetCurPosition(int position)
510 {
511 CSingleLock sync(&m_critical, TRUE);
512 double pos_sec = static_cast<double>(position) / 1000.0;
513 QWORD pos_bytes;
514 pos_bytes = BASS_ChannelSeconds2Bytes(m_musicStream, pos_sec);
515 BASS_ChannelSetPosition(m_musicStream, pos_bytes, BASS_POS_BYTE);
516 m_midi_lyric.midi_lyric.clear();
517 GetMidiPosition();
518 }
519
GetAudioInfo(SongInfo & song_info,int flag)520 void CBassCore::GetAudioInfo(SongInfo & song_info, int flag)
521 {
522 CSingleLock sync(&m_critical, TRUE);
523 GetBASSAudioInfo(m_musicStream, song_info, flag);
524 }
525
GetAudioInfo(const wchar_t * file_path,SongInfo & song_info,int flag)526 void CBassCore::GetAudioInfo(const wchar_t * file_path, SongInfo & song_info, int flag)
527 {
528 HSTREAM hStream;
529 if (song_info.file_path.empty())
530 song_info.file_path = file_path;
531 hStream = BASS_StreamCreateFile(FALSE, file_path, 0, 0, BASS_SAMPLE_FLOAT);
532 GetBASSAudioInfo(hStream, song_info, flag);
533 BASS_StreamFree(hStream);
534 }
535
EncodeAudio(SongInfo song_info,const wstring & dest_file_path,EncodeFormat encode_format,void * encode_para,int dest_freq,EncodeAudioProc proc)536 bool CBassCore::EncodeAudio(SongInfo song_info, const wstring& dest_file_path, EncodeFormat encode_format, void* encode_para, int dest_freq, EncodeAudioProc proc)
537 {
538 wstring out_file_path_temp = CCommon::GetTemplatePath() + CONVERTING_TEMP_FILE_NAME; //转换时的临时文件名
539
540 //创建解码通道
541 const int BUFF_SIZE{ 20000 };
542 // char buff[BUFF_SIZE];
543 std::unique_ptr<char[]> buff(new char[BUFF_SIZE]);
544 HSTREAM hStream = BASS_StreamCreateFile(FALSE, song_info.file_path.c_str(), 0, 0, BASS_STREAM_DECODE/* | BASS_SAMPLE_FLOAT*/);
545 if (hStream == 0)
546 {
547 proc(CONVERT_ERROR_FILE_CANNOT_OPEN);
548 return false;
549 }
550
551 //获取通道信息
552 BASS_CHANNELINFO channel_info;
553 BASS_ChannelGetInfo(hStream, &channel_info);
554 bool is_midi = (CAudioCommon::GetAudioTypeByBassChannel(channel_info.ctype) == AU_MIDI);
555 if (is_midi)
556 {
557 bool sf2_loaded = (CBassCore::m_bass_midi_lib.IsSucceed() && CBassCore::m_sfont.font != 0);
558 if (sf2_loaded)
559 {
560 CBassCore::m_bass_midi_lib.BASS_MIDI_StreamSetFonts(hStream, &CBassCore::m_sfont, 1);
561 }
562 else
563 {
564 BASS_StreamFree(hStream);
565 //::PostMessage(pthis->GetSafeHwnd(), WM_CONVERT_PROGRESS, file_index, CONVERT_ERROR_MIDI_NO_SF2);
566 proc(CONVERT_ERROR_MIDI_NO_SF2);
567 return false;
568 }
569 }
570
571 //转换采样频率
572 HSTREAM hStreamOld = 0;
573 if (dest_freq > 0 && dest_freq != channel_info.freq)
574 {
575 hStreamOld = hStream;
576 hStream = m_bass_mix_lib.BASS_Mixer_StreamCreate(dest_freq, channel_info.chans, BASS_MIXER_END | BASS_STREAM_DECODE);
577 if (hStream != 0)
578 {
579 m_bass_mix_lib.BASS_Mixer_StreamAddChannel(hStream, hStreamOld, 0);
580 }
581 else
582 {
583 hStream = hStreamOld;
584 hStreamOld = 0;
585 }
586 }
587
588 //获取流的长度
589 QWORD length = BASS_ChannelGetLength(hStreamOld != 0 ? hStreamOld : hStream, 0);
590 if (hStreamOld != 0 && channel_info.freq != 0) //如果开启了转换采样频率
591 length = length * dest_freq / channel_info.freq;
592 if (length == 0) length = 1; //防止length作为除数时为0
593
594 //如果转换的音频是cue音轨,则先定位到曲目开始处
595 if (song_info.is_cue)
596 {
597 CBassCore::SetCurrentPosition(hStreamOld != 0 ? hStreamOld : hStream, song_info.start_pos.toInt());
598 }
599
600 HENCODE hEncode;
601 if (encode_format != EncodeFormat::WMA)
602 {
603 //设置解码器命令行参数
604 wstring cmdline;
605 switch (encode_format)
606 {
607 case EncodeFormat::MP3:
608 {
609 if (encode_para == nullptr)
610 break;
611 MP3EncodePara* mp3_para = (MP3EncodePara*)encode_para;
612 //设置lame命令行参数
613 cmdline = m_encode_dir;
614 cmdline += L"lame.exe ";
615 cmdline += mp3_para->cmd_para;
616 cmdline += L" - \"";
617 cmdline += out_file_path_temp;
618 cmdline.push_back(L'\"');
619 }
620 break;
621 case EncodeFormat::OGG:
622 {
623 if (encode_para == nullptr)
624 break;
625 OggEncodePara* ogg_para = (OggEncodePara*)encode_para;
626
627 cmdline = m_encode_dir;
628 CString str;
629 str.Format(_T("oggenc -q %d"), ogg_para->encode_quality);
630 cmdline += str;
631 cmdline += L" -o \"";
632 cmdline += dest_file_path;
633 cmdline += L"\" -";
634 }
635 break;
636 case EncodeFormat::FLAC:
637 {
638 if (encode_para == nullptr)
639 break;
640 FlacEncodePara* flac_para = (FlacEncodePara*)encode_para;
641 cmdline = m_encode_dir;
642 cmdline += _T("flac.exe ");
643 cmdline += flac_para->cmd_para.c_str();
644 cmdline += L" -o \"";
645 cmdline += dest_file_path;
646 cmdline += L"\" -";
647 }
648 break;
649 default:
650 cmdline = dest_file_path;
651 }
652 //开始解码
653 hEncode = m_bass_encode_lib.BASS_Encode_StartW(hStream, cmdline.c_str(), BASS_ENCODE_AUTOFREE | (encode_format == EncodeFormat::WAV ? BASS_ENCODE_PCM : 0), NULL, 0);
654 if (hEncode == 0)
655 {
656 BASS_StreamFree(hStream);
657 if (hStreamOld != 0)
658 BASS_StreamFree(hStreamOld);
659 proc(CONVERT_ERROR_ENCODE_CHANNEL_FAILED);
660 return false;
661 }
662 }
663 else //输出为WMA时使用专用的编码器
664 {
665 if (!m_bass_wma_lib.IsSucceed())
666 {
667 BASS_StreamFree(hStream);
668 if (hStreamOld != 0)
669 BASS_StreamFree(hStreamOld);
670 return false;
671 }
672 //开始解码
673 if (encode_para == nullptr)
674 return false;
675 WmaEncodePara* wma_para = (WmaEncodePara*)encode_para;
676 int wma_bitrate;
677 if (wma_para->cbr)
678 wma_bitrate = wma_para->cbr_bitrate * 1000;
679 else
680 wma_bitrate = wma_para->vbr_quality;
681 hEncode = m_bass_wma_lib.BASS_WMA_EncodeOpenFileW(hStream, NULL, BASS_WMA_ENCODE_STANDARD | BASS_WMA_ENCODE_SOURCE, wma_bitrate, dest_file_path.c_str());
682 int error = BASS_ErrorGetCode();
683 int error_code{ CONVERT_ERROR_ENCODE_CHANNEL_FAILED };
684 //如果出现了错误,则写入错误日志
685 if (error != 0)
686 {
687 wstring log_str = theApp.m_str_table.LoadTextFormat(L"LOG_BASS_FORMAT_CONVERT_ERROR", { song_info.file_path, L"WMA", error });
688 theApp.WriteLog(log_str);
689 switch (error)
690 {
691 case BASS_ERROR_WMA:
692 error_code = CONVERT_ERROR_WMA_NO_WMP9_OR_LATER;
693 break;
694 case BASS_ERROR_NOTAVAIL:
695 error_code = CONVERT_ERROR_WMA_NO_SUPPORTED_ENCODER;
696 break;
697 default:
698 break;
699 }
700 }
701 if (hEncode == 0)
702 {
703 BASS_StreamFree(hStream);
704 if (hStreamOld != 0)
705 BASS_StreamFree(hStreamOld);
706 proc(error_code);
707 return false;
708 }
709 }
710
711 while (BASS_ChannelIsActive(hStream) != BASS_ACTIVE_STOPPED)
712 {
713 if (theApp.m_format_convert_dialog_exit)
714 {
715 m_bass_encode_lib.BASS_Encode_Stop(hEncode);
716 BASS_StreamFree(hStream);
717 if (hStreamOld != 0)
718 BASS_StreamFree(hStreamOld);
719 return false;
720 }
721 // BASS_ChannelGetData(hStream, buff, BUFF_SIZE);
722 BASS_ChannelGetData(hStream, buff.get(), BUFF_SIZE);
723 //if (m_bass_encode_lib.BASS_Encode_IsActive(hStream) == 0)
724 //{
725 // m_bass_encode_lib.BASS_Encode_Stop(hEncode);
726 // BASS_StreamFree(hStream);
727 //}
728
729 //获取转换百分比
730 int percent;
731 static int last_percent{ -1 };
732 if (!song_info.is_cue)
733 {
734 QWORD position = BASS_ChannelGetPosition(hStream, 0);
735 percent = static_cast<int>(position * 100 / length);
736 }
737 else
738 {
739 int cue_position = CBassCore::GetBASSCurrentPosition(hStreamOld != 0 ? hStreamOld : hStream) - song_info.start_pos.toInt();
740 int cue_length = song_info.length().toInt();
741 percent = static_cast<int>(cue_position * 100 / cue_length);
742 if (percent == 100)
743 break;
744 }
745 if (percent < 0 || percent>100)
746 {
747 proc(CONVERT_ERROR_ENCODE_PARA_ERROR);
748 BASS_StreamFree(hStream);
749 if (hStreamOld != 0)
750 BASS_StreamFree(hStreamOld);
751 return false;
752 }
753 if (last_percent != percent)
754 {
755 proc(percent);
756 }
757 last_percent = percent;
758 }
759
760 BASS_StreamFree(hStream);
761 if (hStreamOld != 0)
762 BASS_StreamFree(hStreamOld);
763
764 //由于在转换mp3文件时将目标文件输出到了临时目录,因此转换完成后将此文件移动到输出目录
765 if (encode_format == EncodeFormat::MP3)
766 {
767 CFilePathHelper out_file_path_helper{ dest_file_path };
768 CommonDialogMgr::MoveAFile(AfxGetMainWnd()->GetSafeHwnd(), out_file_path_temp, out_file_path_helper.GetDir());
769 if (CCommon::FileExist(out_file_path_helper.GetFilePath()))
770 CommonDialogMgr::DeleteAFile(AfxGetMainWnd()->GetSafeHwnd(), out_file_path_helper.GetFilePath());
771 CCommon::FileRename(out_file_path_helper.GetDir() + CONVERTING_TEMP_FILE_NAME, out_file_path_helper.GetFileName());
772 }
773 return true;
774 }
775
InitEncoder()776 bool CBassCore::InitEncoder()
777 {
778 wstring encode_dll_path;
779 wstring wma_dll_path;
780 wstring plugin_dir;
781 m_encode_dir = theApp.m_local_dir + L"Encoder\\";
782 plugin_dir = theApp.m_local_dir + L"Plugins\\";
783 encode_dll_path = m_encode_dir + L"bassenc.dll";
784 m_bass_encode_lib.Init(encode_dll_path);
785
786 wma_dll_path = plugin_dir + L"basswma.dll";
787 m_bass_wma_lib.Init(wma_dll_path);
788
789 m_bass_mix_lib.Init(m_encode_dir + L"bassmix.dll");
790
791 return m_bass_encode_lib.IsSucceed();
792 }
793
UnInitEncoder()794 void CBassCore::UnInitEncoder()
795 {
796 m_bass_encode_lib.UnInit();
797 m_bass_wma_lib.UnInit();
798 m_bass_mix_lib.UnInit();
799 }
800
IsFreqConvertAvailable()801 bool CBassCore::IsFreqConvertAvailable()
802 {
803 return m_bass_mix_lib.IsSucceed();
804 }
805
IsMidi()806 bool CBassCore::IsMidi()
807 {
808 return m_is_midi;
809 }
810
IsMidiConnotPlay()811 bool CBassCore::IsMidiConnotPlay()
812 {
813 return (m_is_midi && m_sfont.font == 0);
814 }
815
GetMidiInnerLyric()816 std::wstring CBassCore::GetMidiInnerLyric()
817 {
818 return m_midi_lyric.midi_lyric;
819 }
820
GetMidiInfo()821 MidiInfo CBassCore::GetMidiInfo()
822 {
823 return m_midi_info;
824 }
825
MidiNoLyric()826 bool CBassCore::MidiNoLyric()
827 {
828 return m_midi_lyric.midi_no_lyric;
829 }
830
GetPlayingState()831 PlayingState CBassCore::GetPlayingState()
832 {
833 DWORD state = BASS_ChannelIsActive(m_musicStream);
834 if (state == BASS_ACTIVE_PLAYING)
835 return PS_PLAYING;
836 else if (state == BASS_ACTIVE_PAUSED)
837 return PS_PAUSED;
838 else
839 return PS_STOPED;
840 }
841
ApplyEqualizer(int channel,int gain)842 void CBassCore::ApplyEqualizer(int channel, int gain)
843 {
844 if (channel < 0 || channel >= EQU_CH_NUM) return;
845 //if (!m_equ_enable) return;
846 if (gain < -15) gain = -15;
847 if (gain > 15) gain = 15;
848 BASS_DX8_PARAMEQ parameq;
849 parameq.fBandwidth = 30;
850 parameq.fCenter = FREQ_TABLE[channel];
851 parameq.fGain = static_cast<float>(gain);
852 BASS_FXSetParameters(m_equ_handle[channel], ¶meq);
853
854 }
855
SetReverb(int mix,int time)856 void CBassCore::SetReverb(int mix, int time)
857 {
858 BASS_DX8_REVERB parareverb;
859 parareverb.fInGain = 0;
860 //parareverb.fReverbMix = static_cast<float>(mix) / 100 * 96 - 96;
861 parareverb.fReverbMix = static_cast<float>(std::pow(static_cast<double>(mix) / 100, 0.1) * 96 - 96);
862 parareverb.fReverbTime = static_cast<float>(time * 10);
863 parareverb.fHighFreqRTRatio = 0.001f;
864 BASS_FXSetParameters(m_reverb_handle, ¶reverb);
865 }
866
ClearReverb()867 void CBassCore::ClearReverb()
868 {
869 BASS_DX8_REVERB parareverb;
870 parareverb.fInGain = 0;
871 parareverb.fReverbMix = -96;
872 parareverb.fReverbTime = 0.001f;
873 parareverb.fHighFreqRTRatio = 0.001f;
874 BASS_FXSetParameters(m_reverb_handle, ¶reverb);
875 }
876
GetFFTData(float fft_data[FFT_SAMPLE])877 void CBassCore::GetFFTData(float fft_data[FFT_SAMPLE])
878 {
879 BASS_ChannelGetData(m_musicStream, fft_data, BASS_DATA_FFT512);
880 }
881
GetErrorCode()882 int CBassCore::GetErrorCode()
883 {
884 m_error_code = BASS_ErrorGetCode();
885 return m_error_code;
886 }
887
GetErrorInfo(int error_code)888 std::wstring CBassCore::GetErrorInfo(int error_code)
889 {
890 // 这个方法获取写入错误日志的字符串,后面会附加CPlayer的方法名
891 wstring info = theApp.m_str_table.LoadTextFormat(L"LOG_BASS_ERROR", { error_code, m_file_path });
892 return info;
893 }
894
GetErrorInfo()895 std::wstring CBassCore::GetErrorInfo()
896 {
897 // 这个方法获取错误时状态栏显示的错误字符串“播放出错: <%1%>”
898 int error_code = BASS_ErrorGetCode();
899 wstring info = theApp.m_str_table.LoadTextFormat(L"UI_TXT_PLAYSTATUS_ERROR_CORE_BASS", { error_code });
900 return info;
901 }
902
903 //int CBassCore::GetDeviceCount()
904 //{
905 // BASS_DEVICEINFO info;
906 // int count{};
907 // for (int i = 0; BASS_GetDeviceInfo(i, &info); i++)
908 // if (info.flags&BASS_DEVICE_ENABLED) // device is enabled
909 // count++; // count it
910 // return count;
911 //}
912
IsVolumeFadingOut()913 bool CBassCore::IsVolumeFadingOut()
914 {
915 return m_fading;
916 }
917
GetBASSCurrentPosition(HSTREAM hStream)918 int CBassCore::GetBASSCurrentPosition(HSTREAM hStream)
919 {
920 QWORD pos_bytes;
921 pos_bytes = BASS_ChannelGetPosition(hStream, BASS_POS_BYTE);
922 double pos_sec;
923 pos_sec = BASS_ChannelBytes2Seconds(hStream, pos_bytes);
924 return static_cast<int>(pos_sec * 1000);
925 }
926
GetBASSSongLength(HSTREAM hStream)927 Time CBassCore::GetBASSSongLength(HSTREAM hStream)
928 {
929 QWORD lenght_bytes;
930 lenght_bytes = BASS_ChannelGetLength(hStream, BASS_POS_BYTE);
931 double length_sec;
932 length_sec = BASS_ChannelBytes2Seconds(hStream, lenght_bytes);
933 int song_length_int = static_cast<int>(length_sec * 1000);
934 if (song_length_int <= -1000) song_length_int = 0;
935 return Time(song_length_int); //将长度转换成Time结构
936 }
937
SetCurrentPosition(HSTREAM hStream,int position)938 void CBassCore::SetCurrentPosition(HSTREAM hStream, int position)
939 {
940 double pos_sec = static_cast<double>(position) / 1000.0;
941 QWORD pos_bytes;
942 pos_bytes = BASS_ChannelSeconds2Bytes(hStream, pos_sec);
943 BASS_ChannelSetPosition(hStream, pos_bytes, BASS_POS_BYTE);
944 }
945