@@ -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+
10561147void 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
10721163AudioService::~AudioService ()
10731164{
1165+ bDrawing = false ;
1166+ mtxDrawGraph.lock ();
1167+ mtxDrawGraph.unlock ();
1168+
10741169 delete pRndGen;
10751170
10761171 bMonitorTracks = false ;
0 commit comments