Skip to content
This repository was archived by the owner on May 11, 2022. It is now read-only.

Commit 3d6b336

Browse files
committed
v1.15
1 parent 575098c commit 3d6b336

File tree

12 files changed

+271
-132
lines changed

12 files changed

+271
-132
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
SOFTWARE.
2222

2323

24-
Bloody Player uses FMOD, it's license shown below:
24+
Bloody Player uses FMOD, it's license is shown below:
2525

2626
FMOD END USER LICENCE AGREEMENT
2727
===============================

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Bloody Player
2-
Bloody Player is a simple audio player created using Qt, FMOD and love.
2+
Bloody Player is an audio player created using Qt, FMOD, and love.<br><br>
3+
Features:
4+
- Dark-red design.
5+
- Drag'n'Drop tracks right to the Bloody Player window to add tracks to the tracklist. You can also drag'n'drop folders to add tracks from it.
6+
- Save the current tracklist and open it later.
7+
- Add sound effects or load your VST plugin.
8+
- Move tracks in the tracklist or delete some of them by right-clicking on the track or using hotkeys.
9+
- Click on the horizontal graph displaying amplitude from time to change the current track position.
10+
- Use buttons under the volume slider to set "Repeat Track" / "Random Track" functions.<br><br>
311
<p align="center">
412
<img width="600" height="400" src="screenshot.png">
513
</p>

ide/BloodyPlayer.pro.user

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE QtCreatorProject>
3-
<!-- Written by QtCreator 4.9.2, 2019-08-14T20:32:13. -->
3+
<!-- Written by QtCreator 4.9.2, 2019-08-16T18:43:51. -->
44
<qtcreator>
55
<data>
66
<variable>EnvironmentId</variable>

screenshot.png

41.1 KB
Loading

src/Model/AudioService/audioservice.cpp

Lines changed: 117 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ AudioService::AudioService(MainWindow* pMainWindow)
2727
bIsSomeTrackPlaying = false;
2828
bRepeatTrack = false;
2929
bRandomNextTrack = false;
30+
bDrawing = false;
31+
bCurrentTrackPaused = false;
3032

3133
// FX
3234
pPitch = nullptr;
@@ -325,7 +327,7 @@ void AudioService::addTracks(std::vector<wchar_t*> paths)
325327
pMainWindow->hideWaitWindow();
326328

327329
std::this_thread::sleep_for(std::chrono::milliseconds(100));
328-
pMainWindow->setFocusOnTrack(tracks.size() - 1);
330+
if (tracks.size() > 0) pMainWindow->setFocusOnTrack(tracks.size() - 1);
329331

330332
mtxTracksVec.unlock();
331333
return;
@@ -360,7 +362,7 @@ void AudioService::addTracks(std::vector<wchar_t*> paths)
360362
pMainWindow->hideWaitWindow();
361363

362364
std::this_thread::sleep_for(std::chrono::milliseconds(100));
363-
pMainWindow->setFocusOnTrack(tracks.size() - 1);
365+
if (tracks.size() > 0) pMainWindow->setFocusOnTrack(tracks.size() - 1);
364366

365367
mtxTracksVec.unlock();
366368
}
@@ -373,25 +375,27 @@ void AudioService::playTrack(size_t iTrackIndex, bool bDontLockMutex)
373375

374376
if ( iTrackIndex < tracks.size() )
375377
{
378+
if ( ((bCurrentTrackPaused == false) && (bIsSomeTrackPlaying == false)) || (iTrackIndex != iCurrentlyPlayingTrackIndex) )
379+
{
380+
// Add new graph
381+
std::thread drawGraphThread(&AudioService::drawGraph, this, iTrackIndex);
382+
drawGraphThread.detach();
383+
}
384+
385+
376386
// Play track
377387
if (bIsSomeTrackPlaying)
378388
{
379389
if (iTrackIndex != iCurrentlyPlayingTrackIndex)
380390
{
381391
tracks[iCurrentlyPlayingTrackIndex]->stopTrack();
382392
pMainWindow->removePlayingOnTrack(iCurrentlyPlayingTrackIndex);
383-
pMainWindow->clearGraph();
384-
}
385-
else
386-
{
387-
pMainWindow->clearGraph();
388393
}
389394
}
390395
else if (bCurrentTrackPaused && (iTrackIndex != iCurrentlyPlayingTrackIndex))
391396
{
392397
tracks[iCurrentlyPlayingTrackIndex]->stopTrack();
393398
pMainWindow->removePlayingOnTrack(iCurrentlyPlayingTrackIndex);
394-
pMainWindow->clearGraph();
395399
}
396400

397401
if ( tracks[iTrackIndex]->playTrack(fCurrentVolume) )
@@ -424,12 +428,16 @@ void AudioService::setTrackPos(unsigned int graphPos)
424428

425429
if ( (tracks.size() > 0) && (bIsSomeTrackPlaying) )
426430
{
427-
// static_cast<unsigned long long> because overflow may occur if the track is longer than 70 minutes, for example: graphPos = 800 and track length is 110 minutes.
428-
unsigned int posInMS = static_cast<unsigned int>(static_cast<unsigned long long>(graphPos) * tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS() / MAX_X_AXIS_VALUE);
429-
if ( tracks[iCurrentlyPlayingTrackIndex]->setPositionInMS( posInMS ) )
431+
// track->getMaxValueOnGraph() - 100%
432+
// graphPos - x%
433+
434+
// cast to unsigned long long to avoid overflow
435+
unsigned int iPosInPercent = static_cast<unsigned int>(static_cast<unsigned long long>(graphPos) * 100 / static_cast<double>(tracks[iCurrentlyPlayingTrackIndex]->getMaxValueOnGraph()));
436+
double fPosMult = iPosInPercent / 100.0;
437+
unsigned int iPosInMS = static_cast<unsigned int>(tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS() * fPosMult);
438+
if ( tracks[iCurrentlyPlayingTrackIndex]->setPositionInMS(iPosInMS) )
430439
{
431-
pMainWindow->clearGraph();
432-
pMainWindow->setCurrentPos( static_cast<int>(graphPos), tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
440+
pMainWindow->setCurrentPos(fPosMult, tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
433441
}
434442
}
435443

@@ -472,7 +480,7 @@ void AudioService::stopTrack()
472480
tracks[iCurrentlyPlayingTrackIndex]->stopTrack();
473481
bIsSomeTrackPlaying = false;
474482
bCurrentTrackPaused = true;
475-
pMainWindow->clearGraph();
483+
pMainWindow->clearGraph(true);
476484
}
477485

478486
mtxTracksVec.unlock();
@@ -554,6 +562,13 @@ void AudioService::removeTrack(size_t iTrackIndex)
554562

555563
if ( iTrackIndex < tracks.size() )
556564
{
565+
if ((bIsSomeTrackPlaying || bCurrentTrackPaused) && (iCurrentlyPlayingTrackIndex == iTrackIndex))
566+
{
567+
bDrawing = false;
568+
mtxDrawGraph.lock();
569+
mtxDrawGraph.unlock();
570+
}
571+
557572
delete tracks[iTrackIndex];
558573
tracks.erase( tracks.begin() + iTrackIndex );
559574

@@ -562,19 +577,20 @@ void AudioService::removeTrack(size_t iTrackIndex)
562577
bMonitorTracks = false;
563578
bIsSomeTrackPlaying = false;
564579
bCurrentTrackPaused = false;
565-
pMainWindow->clearGraph();
566580
iCurrentlyPlayingTrackIndex = 0;
567-
std::this_thread::sleep_for(std::chrono::milliseconds(MONITOR_TRACK_INTERVAL_MS));
581+
pMainWindow->clearGraph();
568582
}
569583
else if (bIsSomeTrackPlaying || bCurrentTrackPaused)
570584
{
571585
if (iTrackIndex == iCurrentlyPlayingTrackIndex)
572586
{
573587
bIsSomeTrackPlaying = false;
588+
bCurrentTrackPaused = false;
574589
iCurrentlyPlayingTrackIndex = 0;
575590

576591
// Clear Track Name and Track Info
577592
pMainWindow->setPlayingOnTrack(0, true);
593+
578594
pMainWindow->clearGraph();
579595
}
580596
else if ( (iCurrentlyPlayingTrackIndex != 0) && (iTrackIndex < iCurrentlyPlayingTrackIndex) )
@@ -596,12 +612,13 @@ void AudioService::clearPlaylist()
596612
{
597613
mtxTracksVec.lock();
598614

615+
bDrawing = false;
616+
mtxDrawGraph.lock();
617+
mtxDrawGraph.unlock();
599618

600619
bMonitorTracks = false;
601-
602-
std::this_thread::sleep_for(std::chrono::milliseconds(MONITOR_TRACK_INTERVAL_MS));
603-
604620
bIsSomeTrackPlaying = false;
621+
605622
iCurrentlyPlayingTrackIndex = 0;
606623

607624
for (size_t i = 0; i < tracks.size(); i++)
@@ -612,7 +629,6 @@ void AudioService::clearPlaylist()
612629

613630
fCurrentVolume = DEFAULT_VOLUME;
614631

615-
616632
mtxTracksVec.unlock();
617633
}
618634

@@ -1042,8 +1058,12 @@ void AudioService::monitorTrack()
10421058
}
10431059
else
10441060
{
1045-
unsigned int pos = MAX_X_AXIS_VALUE * tracks[iCurrentlyPlayingTrackIndex]->getPositionInMS() / tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS();
1046-
pMainWindow->setCurrentPos( static_cast<int>(pos), tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
1061+
// track->getLengthInMS() - 1.0
1062+
// track->getPositionInMS() - x
1063+
1064+
double x = static_cast<double>(tracks[iCurrentlyPlayingTrackIndex]->getPositionInMS()) / tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS();
1065+
1066+
pMainWindow->setCurrentPos(x, tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
10471067
}
10481068
}
10491069

@@ -1053,6 +1073,77 @@ void AudioService::monitorTrack()
10531073
}
10541074
}
10551075

1076+
void AudioService::drawGraph(size_t iTrackIndex)
1077+
{
1078+
if (bDrawing)
1079+
{
1080+
// Some thread is drawing, stop it
1081+
bDrawing = false;
1082+
}
1083+
1084+
mtxDrawGraph.lock();
1085+
bDrawing = true;
1086+
1087+
1088+
pMainWindow->clearGraph();
1089+
1090+
// this value combines 'iSamplesInOne' samples in one to store less points for graph in memory
1091+
// more than '200' on a track that is about 5 minutes long looks bad
1092+
// for example 2.5 min track with 'iSamplesInOne' = 100, adds like 3 MB to RAM
1093+
// but less value can fill RAM very bad
1094+
unsigned int iSamplesInOne = 150;
1095+
// so we calculate 'iSamplesInOne' like this:
1096+
// 3000 ('iSamplesInOne') - 6000 (sec.)
1097+
// x ('iSamplesInOne') - track length (in sec.)
1098+
1099+
// here we do: 3000 * (tracks[iTrackIndex]->getLengthInMS() / 1000) / 6000, but we can replace this with just:
1100+
iSamplesInOne = tracks[iTrackIndex]->getLengthInMS() * 3 / 6000;
1101+
if (iSamplesInOne == 0) iSamplesInOne = 1;
1102+
1103+
unsigned int iTempMax = tracks[iTrackIndex]->getLengthInPCMbytes() / 4 / iSamplesInOne;
1104+
pMainWindow->setXMaxToGraph(iTempMax);
1105+
tracks[iTrackIndex]->setMaxPosInGraph(iTempMax);
1106+
1107+
tracks[iTrackIndex]->createDummySound();
1108+
1109+
// 2 MB because you need to multiply this value by 2 (because of short int type of buffer).
1110+
unsigned int iBufferSize = 1048576;
1111+
unsigned int iGraphMax = 0;
1112+
char result = 1;
1113+
1114+
do
1115+
{
1116+
short int* pSamples = new short int[iBufferSize];
1117+
unsigned int iActuallyRead;
1118+
result = tracks[iTrackIndex]->getPCMSamples(pSamples, iBufferSize * 2, &iActuallyRead);
1119+
1120+
if (result == 0)
1121+
{
1122+
// error
1123+
delete[] pSamples;
1124+
break;
1125+
}
1126+
1127+
// Because 'iActuallyRead' is amount of L and R samples and we in MainWindow mix L and R channels in one.
1128+
iGraphMax += iActuallyRead / 2 / iSamplesInOne;
1129+
1130+
pMainWindow->addDataToGraph(pSamples, iActuallyRead, iSamplesInOne);
1131+
1132+
}while ( (result == 1) && (bDrawing) );
1133+
1134+
if (bDrawing)
1135+
{
1136+
pMainWindow->setXMaxToGraph(iGraphMax);
1137+
tracks[iTrackIndex]->setMaxPosInGraph(iGraphMax);
1138+
}
1139+
1140+
tracks[iTrackIndex]->releaseDummySound();
1141+
1142+
1143+
bDrawing = false;
1144+
mtxDrawGraph.unlock();
1145+
}
1146+
10561147
void AudioService::threadAddTracks(std::vector<wchar_t*> paths, bool* done, int* allCount, int all)
10571148
{
10581149
for (size_t i = 0; i < paths.size(); i++)
@@ -1071,6 +1162,10 @@ void AudioService::threadAddTracks(std::vector<wchar_t*> paths, bool* done, int*
10711162

10721163
AudioService::~AudioService()
10731164
{
1165+
bDrawing = false;
1166+
mtxDrawGraph.lock();
1167+
mtxDrawGraph.unlock();
1168+
10741169
delete pRndGen;
10751170

10761171
bMonitorTracks = false;

src/Model/AudioService/audioservice.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ class AudioService
105105
// Will switch to next track if one's ended
106106
void monitorTrack();
107107

108+
void drawGraph(size_t iTrackIndex);
109+
108110

109111
FMOD::System* pSystem;
110112
MainWindow* pMainWindow;
@@ -121,6 +123,9 @@ class AudioService
121123

122124
std::vector<Track*> tracks;
123125

126+
// Graph draw
127+
bool bDrawing;
128+
std::mutex mtxDrawGraph;
124129

125130
bool bIsSomeTrackPlaying;
126131
bool bCurrentTrackPaused;

0 commit comments

Comments
 (0)