@@ -23,17 +23,7 @@ public Player(final File inputFile) throws IOException, FileException {
2323 wavFrames = decoder .processFrames ();
2424 }
2525
26- private static void printProgress (final long current , final long total ) {
27- final StringBuilder string = new StringBuilder (140 );
28- final int percent = (int ) (current * 100 / total );
29- string .append ('\r' ).append (String .format ("%d%% [" , percent ))
30- .append (String .join ("" , Collections .nCopies (percent / 2 , "=" ))).append ("\u001B [1m>\u001B [0m" )
31- .append (String .join ("" , Collections .nCopies (50 - (percent / 2 ), " " ))).append (']' ).append (" (" )
32- .append (current ).append ('/' ).append (total ).append (')' );
33- System .out .print (string );
34- }
35-
36- public void play () throws LineUnavailableException {
26+ public void play () throws LineUnavailableException , InterruptedException {
3727 // Select audio format parameters
3828 final AudioFormat af = new AudioFormat (decoder .selaFile .getSampleRate (), decoder .selaFile .getBitsPerSample (),
3929 decoder .selaFile .getChannels (), true , false );
@@ -44,14 +34,56 @@ public void play() throws LineUnavailableException {
4434 line .open (af , 2048 * decoder .selaFile .getChannels ());
4535 line .start ();
4636
37+ //Prepare print thread
38+ PlayProgress progress = new PlayProgress (wavFrames .size ());
39+ Thread printThread = new Thread (new ProgressPrinter (progress ));
40+ printThread .start ();
41+
4742 // Output wave form repeatedly
4843 for (int i = 0 ; i < wavFrames .size (); i ++) {
4944 final byte [] bytes = wavFrames .get (i ).getDemuxedShortSamplesInByteArray ();
5045 line .write (bytes , 0 , bytes .length );
51- Player . printProgress (( i + 1 ), wavFrames . size ()) ;
46+ progress . currentFrameNumber ++ ;
5247 }
48+ printThread .join ();
5349 line .drain ();
5450 line .stop ();
5551 line .close ();
5652 }
53+ }
54+
55+ // A separate thread for printing is required since audio lags when we print as well as play audio on single thread on Windows.
56+ class ProgressPrinter implements Runnable {
57+ private PlayProgress progress ;
58+ public ProgressPrinter (PlayProgress progress ) {
59+ this .progress = progress ;
60+ }
61+
62+ public void run () {
63+ while (progress .currentFrameNumber < progress .totalFrameCount ) {
64+ printProgress (progress .currentFrameNumber , progress .totalFrameCount );
65+ }
66+ printProgress (progress .currentFrameNumber , progress .totalFrameCount ); //Print one last time to make it 100%
67+ }
68+
69+ private void printProgress (final long current , final long total ) {
70+ final StringBuilder string = new StringBuilder (140 );
71+ final int percent = (int ) (current * 100 / total );
72+ string .append ('\r' ).append (String .format ("%d%% [" , percent ))
73+ .append (String .join ("" , Collections .nCopies (percent / 2 , "=" ))).append (">" )
74+ .append (String .join ("" , Collections .nCopies (50 - (percent / 2 ), " " ))).append (']' ).append (" (" )
75+ .append (current ).append ('/' ).append (total ).append (')' );
76+ System .out .print (string );
77+ }
78+ }
79+
80+ // Data Class for keeping track of progress. Will be shared between audio thread and print thread
81+ class PlayProgress {
82+ public volatile int currentFrameNumber ;
83+ public final int totalFrameCount ;
84+
85+ public PlayProgress (int totalFrameCount ) {
86+ currentFrameNumber = 0 ;
87+ this .totalFrameCount = totalFrameCount ;
88+ }
5789}
0 commit comments