1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module music_player
/*is aliced*/;
30 // ////////////////////////////////////////////////////////////////////////// //
35 // ////////////////////////////////////////////////////////////////////////// //
36 __gshared
uint vrTotalTimeMsec
= 0;
37 __gshared
uint vrNextTimeMsec
= 0;
38 __gshared
bool vrPaused
= false;
39 __gshared
ubyte vrVolume
= 255;
40 __gshared
bool forceUp
= false;
43 void showProgress (bool endtime
=false) {
44 auto curTime
= (endtime ? vrTotalTimeMsec
: tflChannelPlayTimeMsec("music"));
45 if (curTime
>= vrNextTimeMsec || tflPaused
!= vrPaused || forceUp
) {
46 vrNextTimeMsec
= curTime
+1000;
48 import core
.sys
.posix
.unistd
: write
;
49 import std
.string
: format
;
50 auto pstr
= "\r%02s:%02s/%02s:%02s %3s%%%s\e[K".format(curTime
/1000/60, curTime
/1000%60, vrTotalTimeMsec
/1000/60, vrTotalTimeMsec
/1000%60,
51 100*vrVolume
/255, (vrPaused ?
" [P]" : ""));
52 write(1/*stdout*/, pstr
.ptr
, cast(uint)pstr
.length
);
58 long totalTimeMsec (FileChannel chan
) {
59 auto res
= chan
.totalMsecs
;
60 return (res
>= 0 ? res
: 0);
64 int quality
= TflChannel
.QualityMusic
;
66 enum Action
{ Quit
, Prev
, Next
}
69 if (plidx
>= playlist
.length
) return Action
.Quit
;
71 Action res
= Action
.Next
;
72 FileChannel chan
= FileChannel
.detect(playlist
[plidx
]);
75 foreach (immutable c
; plidx
+1..playlist
.length
) playlist
[c
-1] = playlist
[c
];
81 import core
.stdc
.stdio
;
82 import std
.path
: baseName
;
83 auto bn
= playlist
[plidx
].baseName
;
84 printf("=== [%u/%u] %.*s (%d) ===\n", cast(uint)(plidx
+1), cast(uint)playlist
.length
, cast(uint)bn
.length
, bn
.ptr
, quality
);
87 if (auto vc
= cast(VorbisChannel
)chan
.srcchan
) {
90 auto name
= vc
.vf
.comment_name
;
91 auto value
= vc
.vf
.comment_value
;
92 if (name
is null) break;
93 if (utf8Valid(value
)) value
= recodeToKOI8(value
);
94 writeln(" ", name
, "=", value
);
97 } else if (auto fc
= cast(FlacChannel
)chan
.srcchan
) {
98 foreach (string val
; fc
.comments
) {
100 if (utf8Valid(val
)) val
= recodeToKOI8(val
);
105 vrTotalTimeMsec
= cast(uint)chan
.totalTimeMsec
;
108 if (!tflAddChannel("music", chan
, TFLmusic
, quality
)) {
109 import core
.stdc
.stdio
;
110 fprintf(stderr
, "ERROR: can't add ogg channel!\n");
114 while (tflIsChannelAlive("music")) {
117 if (ttyWaitKey(200)) {
118 auto key
= ttyReadKey();
119 if (key
.key
!= TtyEvent
.Key
.Char
) continue;
120 if (key
.ch
> 127) continue;
121 switch (cast(char)key
.ch
) {
123 tflPaused
= !tflPaused
;
126 if (auto oc
= tflChannelObject("music")) {
132 tflKillChannel("music");
136 tflKillChannel("music");
140 tflKillChannel("music");
146 chan
.volume
= vrVolume
;
151 if (vrVolume
< 255) {
153 chan
.volume
= vrVolume
;
161 assert(!tflIsChannelAlive("music"));
164 { import core
.stdc
.stdio
; printf("\n"); }
166 //foreach (immutable _; 0..100) { import core.sys.posix.unistd : usleep; usleep(1000); }
171 // ////////////////////////////////////////////////////////////////////////// //
172 void main (string
[] args
) {
173 if (ttyIsRedirected
) throw new Exception("no redirects, please!");
175 if (args
.length
< 2) throw new Exception("filename?");
177 bool nomoreargs
= false;
178 bool shuffle
= false;
180 foreach (string arg
; args
[1..$]) {
181 if (args
.length
== 0) continue;
183 if (arg
== "--") { nomoreargs
= true; continue; }
184 if (arg
== "--cubic") { quality
= -1; continue; }
185 if (arg
== "--best") { quality
= 10; continue; }
186 if (arg
== "--shuffle") { shuffle
= true; continue; }
188 if (arg
.length
== 2 && arg
[1] >= '0' && arg
[1] <= '9') { quality
= arg
[1]-'0'; continue; }
189 if (arg
.length
== 3 && arg
[1] == 'q' && arg
[2] >= '0' && arg
[2] <= '9') { quality
= arg
[2]-'0'; continue; }
190 throw new Exception("unknown option: '"~arg
~"'");
193 import std
.file
: exists
;
195 import core
.stdc
.stdio
;
196 printf("skipped '%.*s'\n", cast(uint)arg
.length
, arg
.ptr
);
202 if (playlist
.length
== 0) throw new Exception("no files!");
205 playlist
.randomShuffle
;
209 scope(exit
) ttySetNormal();
212 scope(exit
) tflDeinit();
213 { import std
.stdio
; writeln("latency: ", tflLatency
); }
216 final switch (playFile()) with (Action
) {
217 case Prev
: if (plidx
> 0) --plidx
; break;
218 case Next
: ++plidx
; break;
219 case Quit
: break mainloop
;