|
1
|
1 #include "foobar2000-sdk-pch.h"
|
|
|
2 #include "playback_control.h"
|
|
|
3 #include "titleformat.h"
|
|
|
4
|
|
|
5 static double parseFraction(const char * fraction) {
|
|
|
6 unsigned v = 0, d = 1;
|
|
|
7 while(pfc::char_is_numeric( *fraction) ) {
|
|
|
8 d *= 10;
|
|
|
9 v *= 10;
|
|
|
10 v += (unsigned) ( *fraction - '0' );
|
|
|
11 ++fraction;
|
|
|
12 }
|
|
|
13 PFC_ASSERT( *fraction == 0 );
|
|
|
14 return (double)v / (double)d;
|
|
|
15 }
|
|
|
16
|
|
|
17 static double parse_time(const char * time) {
|
|
|
18 unsigned vTotal = 0, vCur = 0;
|
|
|
19 for(;;) {
|
|
|
20 char c = *time++;
|
|
|
21 if (c == 0) return (double) (vTotal + vCur);
|
|
|
22 else if (pfc::char_is_numeric( c ) ) {
|
|
|
23 vCur = vCur * 10 + (unsigned)(c-'0');
|
|
|
24 } else if (c == ':') {
|
|
|
25 if (vCur >= 60) {PFC_ASSERT(!"Invalid input"); return 0; }
|
|
|
26 vTotal += vCur; vCur = 0; vTotal *= 60;
|
|
|
27 } else if (c == '.') {
|
|
|
28 return (double) (vTotal + vCur) + parseFraction(time);
|
|
|
29 } else {
|
|
|
30 PFC_ASSERT(!"Invalid input"); return 0;
|
|
|
31 }
|
|
|
32 }
|
|
|
33 }
|
|
|
34
|
|
|
35 double playback_control::playback_get_length()
|
|
|
36 {
|
|
|
37 double rv = 0;
|
|
|
38 metadb_handle_ptr ptr;
|
|
|
39 if (get_now_playing(ptr))
|
|
|
40 {
|
|
|
41 rv = ptr->get_length();
|
|
|
42 }
|
|
|
43 return rv;
|
|
|
44 }
|
|
|
45
|
|
|
46 double playback_control::playback_get_length_ex() {
|
|
|
47 double rv = 0;
|
|
|
48 metadb_handle_ptr ptr;
|
|
|
49 if (get_now_playing(ptr))
|
|
|
50 {
|
|
|
51 rv = ptr->get_length();
|
|
|
52 if (rv <= 0) {
|
|
|
53 pfc::string8 temp;
|
|
|
54 titleformat_object::ptr script;
|
|
|
55 titleformat_compiler::get()->compile_force(script, "[%length_ex%]");
|
|
|
56 this->playback_format_title(NULL, temp, script, NULL, display_level_titles);
|
|
|
57 if (temp.length() > 0) rv = parse_time(temp);
|
|
|
58 }
|
|
|
59 }
|
|
|
60 return rv;
|
|
|
61 }
|
|
|
62
|
|
|
63
|
|
|
64
|
|
|
65
|
|
|
66
|
|
|
67
|
|
|
68 void playback_control::userPrev() {
|
|
|
69 userActionHook();
|
|
|
70 if (this->is_playing() && this->playback_can_seek() && this->playback_get_position() > 5) {
|
|
|
71 this->playback_seek(0);
|
|
|
72 } else {
|
|
|
73 this->previous();
|
|
|
74 }
|
|
|
75 }
|
|
|
76
|
|
|
77 void playback_control::userNext() {
|
|
|
78 userActionHook();
|
|
|
79 this->start(track_command_next);
|
|
|
80 }
|
|
|
81
|
|
|
82 void playback_control::userMute() {
|
|
|
83 userActionHook();
|
|
|
84 this->volume_mute_toggle();
|
|
|
85 }
|
|
|
86
|
|
|
87 void playback_control::userStop() {
|
|
|
88 userActionHook();
|
|
|
89 this->stop();
|
|
|
90 }
|
|
|
91
|
|
|
92 void playback_control::userPlay() {
|
|
|
93 userActionHook();
|
|
|
94 this->play_or_pause();
|
|
|
95 }
|
|
|
96
|
|
|
97 void playback_control::userPause() {
|
|
|
98 userActionHook();
|
|
|
99 nonUserPause();
|
|
|
100 }
|
|
|
101
|
|
|
102 void playback_control::nonUserPause() {
|
|
|
103 if (this->is_playing()) {
|
|
|
104 this->pause(true);
|
|
|
105 }
|
|
|
106 }
|
|
|
107
|
|
|
108 void playback_control::userStart() {
|
|
|
109 userActionHook();
|
|
|
110 if (this->is_playing()) {
|
|
|
111 this->pause(false);
|
|
|
112 } else {
|
|
|
113 this->start();
|
|
|
114 }
|
|
|
115 }
|
|
|
116 static const double seekDelta = 30;
|
|
|
117 void playback_control::userFastForward() {
|
|
|
118 userActionHook();
|
|
|
119 if (!this->playback_can_seek()) {
|
|
|
120 this->userNext(); return;
|
|
|
121 }
|
|
|
122 this->playback_seek_delta(seekDelta);
|
|
|
123 }
|
|
|
124
|
|
|
125 void playback_control::userRewind() {
|
|
|
126 userActionHook();
|
|
|
127 if (!this->playback_can_seek()) {
|
|
|
128 this->userPrev(); return;
|
|
|
129 }
|
|
|
130 double p = this->playback_get_position();
|
|
|
131 if (p < 0) return;
|
|
|
132 if (p < seekDelta) {
|
|
|
133 if (p < seekDelta / 3) {
|
|
|
134 this->userPrev();
|
|
|
135 } else {
|
|
|
136 this->playback_seek(0);
|
|
|
137 }
|
|
|
138 } else {
|
|
|
139 this->playback_seek_delta(-30);
|
|
|
140 }
|
|
|
141 }
|