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

Commit

Permalink
v1.15
Browse files Browse the repository at this point in the history
  • Loading branch information
Flone-dnb committed Aug 16, 2019
1 parent 575098c commit 3d6b336
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 132 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


Bloody Player uses FMOD, it's license shown below:
Bloody Player uses FMOD, it's license is shown below:

FMOD END USER LICENCE AGREEMENT
===============================
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Bloody Player
Bloody Player is a simple audio player created using Qt, FMOD and love.
Bloody Player is an audio player created using Qt, FMOD, and love.<br><br>
Features:
- Dark-red design.
- 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.
- Save the current tracklist and open it later.
- Add sound effects or load your VST plugin.
- Move tracks in the tracklist or delete some of them by right-clicking on the track or using hotkeys.
- Click on the horizontal graph displaying amplitude from time to change the current track position.
- Use buttons under the volume slider to set "Repeat Track" / "Random Track" functions.<br><br>
<p align="center">
<img width="600" height="400" src="screenshot.png">
</p>
2 changes: 1 addition & 1 deletion ide/BloodyPlayer.pro.user
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.9.2, 2019-08-14T20:32:13. -->
<!-- Written by QtCreator 4.9.2, 2019-08-16T18:43:51. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
Expand Down
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
139 changes: 117 additions & 22 deletions src/Model/AudioService/audioservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ AudioService::AudioService(MainWindow* pMainWindow)
bIsSomeTrackPlaying = false;
bRepeatTrack = false;
bRandomNextTrack = false;
bDrawing = false;
bCurrentTrackPaused = false;

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

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

mtxTracksVec.unlock();
return;
Expand Down Expand Up @@ -360,7 +362,7 @@ void AudioService::addTracks(std::vector<wchar_t*> paths)
pMainWindow->hideWaitWindow();

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

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

if ( iTrackIndex < tracks.size() )
{
if ( ((bCurrentTrackPaused == false) && (bIsSomeTrackPlaying == false)) || (iTrackIndex != iCurrentlyPlayingTrackIndex) )
{
// Add new graph
std::thread drawGraphThread(&AudioService::drawGraph, this, iTrackIndex);
drawGraphThread.detach();
}


// Play track
if (bIsSomeTrackPlaying)
{
if (iTrackIndex != iCurrentlyPlayingTrackIndex)
{
tracks[iCurrentlyPlayingTrackIndex]->stopTrack();
pMainWindow->removePlayingOnTrack(iCurrentlyPlayingTrackIndex);
pMainWindow->clearGraph();
}
else
{
pMainWindow->clearGraph();
}
}
else if (bCurrentTrackPaused && (iTrackIndex != iCurrentlyPlayingTrackIndex))
{
tracks[iCurrentlyPlayingTrackIndex]->stopTrack();
pMainWindow->removePlayingOnTrack(iCurrentlyPlayingTrackIndex);
pMainWindow->clearGraph();
}

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

if ( (tracks.size() > 0) && (bIsSomeTrackPlaying) )
{
// 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.
unsigned int posInMS = static_cast<unsigned int>(static_cast<unsigned long long>(graphPos) * tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS() / MAX_X_AXIS_VALUE);
if ( tracks[iCurrentlyPlayingTrackIndex]->setPositionInMS( posInMS ) )
// track->getMaxValueOnGraph() - 100%
// graphPos - x%

// cast to unsigned long long to avoid overflow
unsigned int iPosInPercent = static_cast<unsigned int>(static_cast<unsigned long long>(graphPos) * 100 / static_cast<double>(tracks[iCurrentlyPlayingTrackIndex]->getMaxValueOnGraph()));
double fPosMult = iPosInPercent / 100.0;
unsigned int iPosInMS = static_cast<unsigned int>(tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS() * fPosMult);
if ( tracks[iCurrentlyPlayingTrackIndex]->setPositionInMS(iPosInMS) )
{
pMainWindow->clearGraph();
pMainWindow->setCurrentPos( static_cast<int>(graphPos), tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
pMainWindow->setCurrentPos(fPosMult, tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
}
}

Expand Down Expand Up @@ -472,7 +480,7 @@ void AudioService::stopTrack()
tracks[iCurrentlyPlayingTrackIndex]->stopTrack();
bIsSomeTrackPlaying = false;
bCurrentTrackPaused = true;
pMainWindow->clearGraph();
pMainWindow->clearGraph(true);
}

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

if ( iTrackIndex < tracks.size() )
{
if ((bIsSomeTrackPlaying || bCurrentTrackPaused) && (iCurrentlyPlayingTrackIndex == iTrackIndex))
{
bDrawing = false;
mtxDrawGraph.lock();
mtxDrawGraph.unlock();
}

delete tracks[iTrackIndex];
tracks.erase( tracks.begin() + iTrackIndex );

Expand All @@ -562,19 +577,20 @@ void AudioService::removeTrack(size_t iTrackIndex)
bMonitorTracks = false;
bIsSomeTrackPlaying = false;
bCurrentTrackPaused = false;
pMainWindow->clearGraph();
iCurrentlyPlayingTrackIndex = 0;
std::this_thread::sleep_for(std::chrono::milliseconds(MONITOR_TRACK_INTERVAL_MS));
pMainWindow->clearGraph();
}
else if (bIsSomeTrackPlaying || bCurrentTrackPaused)
{
if (iTrackIndex == iCurrentlyPlayingTrackIndex)
{
bIsSomeTrackPlaying = false;
bCurrentTrackPaused = false;
iCurrentlyPlayingTrackIndex = 0;

// Clear Track Name and Track Info
pMainWindow->setPlayingOnTrack(0, true);

pMainWindow->clearGraph();
}
else if ( (iCurrentlyPlayingTrackIndex != 0) && (iTrackIndex < iCurrentlyPlayingTrackIndex) )
Expand All @@ -596,12 +612,13 @@ void AudioService::clearPlaylist()
{
mtxTracksVec.lock();

bDrawing = false;
mtxDrawGraph.lock();
mtxDrawGraph.unlock();

bMonitorTracks = false;

std::this_thread::sleep_for(std::chrono::milliseconds(MONITOR_TRACK_INTERVAL_MS));

bIsSomeTrackPlaying = false;

iCurrentlyPlayingTrackIndex = 0;

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

fCurrentVolume = DEFAULT_VOLUME;


mtxTracksVec.unlock();
}

Expand Down Expand Up @@ -1042,8 +1058,12 @@ void AudioService::monitorTrack()
}
else
{
unsigned int pos = MAX_X_AXIS_VALUE * tracks[iCurrentlyPlayingTrackIndex]->getPositionInMS() / tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS();
pMainWindow->setCurrentPos( static_cast<int>(pos), tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
// track->getLengthInMS() - 1.0
// track->getPositionInMS() - x

double x = static_cast<double>(tracks[iCurrentlyPlayingTrackIndex]->getPositionInMS()) / tracks[iCurrentlyPlayingTrackIndex]->getLengthInMS();

pMainWindow->setCurrentPos(x, tracks[iCurrentlyPlayingTrackIndex]->getCurrentTime());
}
}

Expand All @@ -1053,6 +1073,77 @@ void AudioService::monitorTrack()
}
}

void AudioService::drawGraph(size_t iTrackIndex)
{
if (bDrawing)
{
// Some thread is drawing, stop it
bDrawing = false;
}

mtxDrawGraph.lock();
bDrawing = true;


pMainWindow->clearGraph();

// this value combines 'iSamplesInOne' samples in one to store less points for graph in memory
// more than '200' on a track that is about 5 minutes long looks bad
// for example 2.5 min track with 'iSamplesInOne' = 100, adds like 3 MB to RAM
// but less value can fill RAM very bad
unsigned int iSamplesInOne = 150;
// so we calculate 'iSamplesInOne' like this:
// 3000 ('iSamplesInOne') - 6000 (sec.)
// x ('iSamplesInOne') - track length (in sec.)

// here we do: 3000 * (tracks[iTrackIndex]->getLengthInMS() / 1000) / 6000, but we can replace this with just:
iSamplesInOne = tracks[iTrackIndex]->getLengthInMS() * 3 / 6000;
if (iSamplesInOne == 0) iSamplesInOne = 1;

unsigned int iTempMax = tracks[iTrackIndex]->getLengthInPCMbytes() / 4 / iSamplesInOne;
pMainWindow->setXMaxToGraph(iTempMax);
tracks[iTrackIndex]->setMaxPosInGraph(iTempMax);

tracks[iTrackIndex]->createDummySound();

// 2 MB because you need to multiply this value by 2 (because of short int type of buffer).
unsigned int iBufferSize = 1048576;
unsigned int iGraphMax = 0;
char result = 1;

do
{
short int* pSamples = new short int[iBufferSize];
unsigned int iActuallyRead;
result = tracks[iTrackIndex]->getPCMSamples(pSamples, iBufferSize * 2, &iActuallyRead);

if (result == 0)
{
// error
delete[] pSamples;
break;
}

// Because 'iActuallyRead' is amount of L and R samples and we in MainWindow mix L and R channels in one.
iGraphMax += iActuallyRead / 2 / iSamplesInOne;

pMainWindow->addDataToGraph(pSamples, iActuallyRead, iSamplesInOne);

}while ( (result == 1) && (bDrawing) );

if (bDrawing)
{
pMainWindow->setXMaxToGraph(iGraphMax);
tracks[iTrackIndex]->setMaxPosInGraph(iGraphMax);
}

tracks[iTrackIndex]->releaseDummySound();


bDrawing = false;
mtxDrawGraph.unlock();
}

void AudioService::threadAddTracks(std::vector<wchar_t*> paths, bool* done, int* allCount, int all)
{
for (size_t i = 0; i < paths.size(); i++)
Expand All @@ -1071,6 +1162,10 @@ void AudioService::threadAddTracks(std::vector<wchar_t*> paths, bool* done, int*

AudioService::~AudioService()
{
bDrawing = false;
mtxDrawGraph.lock();
mtxDrawGraph.unlock();

delete pRndGen;

bMonitorTracks = false;
Expand Down
5 changes: 5 additions & 0 deletions src/Model/AudioService/audioservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class AudioService
// Will switch to next track if one's ended
void monitorTrack();

void drawGraph(size_t iTrackIndex);


FMOD::System* pSystem;
MainWindow* pMainWindow;
Expand All @@ -121,6 +123,9 @@ class AudioService

std::vector<Track*> tracks;

// Graph draw
bool bDrawing;
std::mutex mtxDrawGraph;

bool bIsSomeTrackPlaying;
bool bCurrentTrackPaused;
Expand Down
Loading

0 comments on commit 3d6b336

Please sign in to comment.