diff options
author | Brandon Low <lostlogic@rockbox.org> | 2006-01-21 23:43:57 +0000 |
---|---|---|
committer | Brandon Low <lostlogic@rockbox.org> | 2006-01-21 23:43:57 +0000 |
commit | 8d5a6609a33f3269bc80975b81e0e859a056d952 (patch) | |
tree | 9bef78c29941956fc6473f58e1657624c150f2d5 /apps/abrepeat.c | |
parent | 0a9179cb0a4bda8191fcfcb45404ea361fcacdc5 (diff) | |
download | rockbox-8d5a6609a33f3269bc80975b81e0e859a056d952.tar.gz rockbox-8d5a6609a33f3269bc80975b81e0e859a056d952.zip |
AB-repeat mode for software codecs. Accessible through menu as a repeat mode, with buttom mappings much like those on other rockbox targets for now.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8409 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/abrepeat.c')
-rw-r--r-- | apps/abrepeat.c | 108 |
1 files changed, 44 insertions, 64 deletions
diff --git a/apps/abrepeat.c b/apps/abrepeat.c index 3a3d5b394d..b83a7b6aa3 100644 --- a/apps/abrepeat.c +++ b/apps/abrepeat.c | |||
@@ -19,16 +19,20 @@ | |||
19 | 19 | ||
20 | #include "abrepeat.h" | 20 | #include "abrepeat.h" |
21 | 21 | ||
22 | #include "settings.h" | ||
23 | #include "audio.h" | ||
24 | #include "kernel.h" | ||
25 | |||
26 | #ifdef HAVE_LCD_BITMAP | ||
27 | #include "lcd.h" | ||
28 | #endif | ||
29 | |||
30 | #ifdef AB_REPEAT_ENABLE | 22 | #ifdef AB_REPEAT_ENABLE |
31 | 23 | ||
24 | unsigned int ab_A_marker IDATA_ATTR = AB_MARKER_NONE; | ||
25 | unsigned int ab_B_marker IDATA_ATTR = AB_MARKER_NONE; | ||
26 | |||
27 | #if (CONFIG_CODEC == SWCODEC) | ||
28 | void ab_end_of_track_report(void) | ||
29 | { | ||
30 | if ( ab_A_marker_set() && ! ab_B_marker_set() ) | ||
31 | { | ||
32 | ab_jump_to_A_marker(); | ||
33 | } | ||
34 | } | ||
35 | #else | ||
32 | static int ab_audio_event_handler(unsigned short event, unsigned long data) | 36 | static int ab_audio_event_handler(unsigned short event, unsigned long data) |
33 | { | 37 | { |
34 | int rc = AUDIO_EVENT_RC_IGNORED; | 38 | int rc = AUDIO_EVENT_RC_IGNORED; |
@@ -38,7 +42,8 @@ static int ab_audio_event_handler(unsigned short event, unsigned long data) | |||
38 | { | 42 | { |
39 | case AUDIO_EVENT_POS_REPORT: | 43 | case AUDIO_EVENT_POS_REPORT: |
40 | { | 44 | { |
41 | if ( ! (audio_status() & AUDIO_STATUS_PAUSE) && ab_reached_B_marker(data) ) | 45 | if ( ! (audio_status() & AUDIO_STATUS_PAUSE) && |
46 | ab_reached_B_marker(data) ) | ||
42 | { | 47 | { |
43 | ab_jump_to_A_marker(); | 48 | ab_jump_to_A_marker(); |
44 | rc = AUDIO_EVENT_RC_HANDLED; | 49 | rc = AUDIO_EVENT_RC_HANDLED; |
@@ -58,6 +63,7 @@ static int ab_audio_event_handler(unsigned short event, unsigned long data) | |||
58 | } | 63 | } |
59 | return rc; | 64 | return rc; |
60 | } | 65 | } |
66 | #endif | ||
61 | 67 | ||
62 | void ab_repeat_init(void) | 68 | void ab_repeat_init(void) |
63 | { | 69 | { |
@@ -65,30 +71,13 @@ void ab_repeat_init(void) | |||
65 | if ( ! ab_initialized ) | 71 | if ( ! ab_initialized ) |
66 | { | 72 | { |
67 | ab_initialized = true; | 73 | ab_initialized = true; |
74 | #if (CONFIG_CODEC != SWCODEC) | ||
68 | audio_register_event_handler(ab_audio_event_handler, | 75 | audio_register_event_handler(ab_audio_event_handler, |
69 | AUDIO_EVENT_POS_REPORT | AUDIO_EVENT_END_OF_TRACK ); | 76 | AUDIO_EVENT_POS_REPORT | AUDIO_EVENT_END_OF_TRACK ); |
77 | #endif | ||
70 | } | 78 | } |
71 | } | 79 | } |
72 | 80 | ||
73 | static unsigned int ab_A_marker = AB_MARKER_NONE; | ||
74 | static unsigned int ab_B_marker = AB_MARKER_NONE; | ||
75 | |||
76 | bool ab_repeat_mode_enabled(void) | ||
77 | { | ||
78 | extern struct user_settings global_settings; | ||
79 | return global_settings.repeat_mode == REPEAT_AB; | ||
80 | } | ||
81 | |||
82 | bool ab_A_marker_set(void) | ||
83 | { | ||
84 | return ab_A_marker != AB_MARKER_NONE; | ||
85 | } | ||
86 | |||
87 | bool ab_B_marker_set(void) | ||
88 | { | ||
89 | return ab_B_marker != AB_MARKER_NONE; | ||
90 | } | ||
91 | |||
92 | unsigned int ab_get_A_marker(void) | 81 | unsigned int ab_get_A_marker(void) |
93 | { | 82 | { |
94 | return ab_A_marker; | 83 | return ab_A_marker; |
@@ -99,24 +88,6 @@ unsigned int ab_get_B_marker(void) | |||
99 | return ab_B_marker; | 88 | return ab_B_marker; |
100 | } | 89 | } |
101 | 90 | ||
102 | bool ab_reached_B_marker(unsigned int song_position) | ||
103 | { | ||
104 | /* following is the size of the window in which we'll detect that the B marker | ||
105 | was hit; it must be larger than the frequency (in milliseconds) at which this | ||
106 | function is called otherwise detection of the B marker will be unreliable; | ||
107 | we assume that this function will be called on each system tick and derive | ||
108 | the window size from this with a generous margin of error (note: the number | ||
109 | of ticks per second is given by HZ) */ | ||
110 | #define B_MARKER_DETECT_WINDOW ((1000/HZ)*10) | ||
111 | if (ab_B_marker != AB_MARKER_NONE) | ||
112 | { | ||
113 | if ( (song_position >= ab_B_marker) | ||
114 | && (song_position <= (ab_B_marker+B_MARKER_DETECT_WINDOW)) ) | ||
115 | return true; | ||
116 | } | ||
117 | return false; | ||
118 | } | ||
119 | |||
120 | /* determines if the given song position is earlier than the A mark; | 91 | /* determines if the given song position is earlier than the A mark; |
121 | intended for use in handling the jump NEXT and PREV commands */ | 92 | intended for use in handling the jump NEXT and PREV commands */ |
122 | bool ab_before_A_marker(unsigned int song_position) | 93 | bool ab_before_A_marker(unsigned int song_position) |
@@ -129,9 +100,9 @@ bool ab_before_A_marker(unsigned int song_position) | |||
129 | intended for use in handling the jump PREV command */ | 100 | intended for use in handling the jump PREV command */ |
130 | bool ab_after_A_marker(unsigned int song_position) | 101 | bool ab_after_A_marker(unsigned int song_position) |
131 | { | 102 | { |
132 | /* following is the size of the virtual A marker; we pretend that the A marker is | 103 | /* following is the size of the virtual A marker; we pretend that the A marker |
133 | larger than a single instant in order to give the user time to hit PREV again to | 104 | is larger than a single instant in order to give the user time to hit PREV again |
134 | jump back to the start of the song; it should be large enough to allow a | 105 | to jump back to the start of the song; it should be large enough to allow a |
135 | reasonable amount of time for the typical user to react */ | 106 | reasonable amount of time for the typical user to react */ |
136 | #define A_MARKER_VIRTUAL_SIZE 1000 | 107 | #define A_MARKER_VIRTUAL_SIZE 1000 |
137 | return (ab_A_marker != AB_MARKER_NONE) | 108 | return (ab_A_marker != AB_MARKER_NONE) |
@@ -140,12 +111,16 @@ reasonable amount of time for the typical user to react */ | |||
140 | 111 | ||
141 | void ab_jump_to_A_marker(void) | 112 | void ab_jump_to_A_marker(void) |
142 | { | 113 | { |
114 | #if (CONFIG_CODEC == SWCODEC) | ||
115 | audio_seamless_seek(ab_A_marker); | ||
116 | #else | ||
143 | bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0; | 117 | bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0; |
144 | if ( ! paused ) | 118 | if ( ! paused ) |
145 | audio_pause(); | 119 | audio_pause(); |
146 | audio_ff_rewind(ab_A_marker); | 120 | audio_ff_rewind(ab_A_marker); |
147 | if ( ! paused ) | 121 | if ( ! paused ) |
148 | audio_resume(); | 122 | audio_resume(); |
123 | #endif | ||
149 | } | 124 | } |
150 | 125 | ||
151 | void ab_reset_markers(void) | 126 | void ab_reset_markers(void) |
@@ -182,37 +157,42 @@ void ab_set_B_marker(unsigned int song_position) | |||
182 | 157 | ||
183 | #ifdef HAVE_LCD_BITMAP | 158 | #ifdef HAVE_LCD_BITMAP |
184 | 159 | ||
185 | static int ab_calc_mark_x_pos(int mark, int capacity, int offset, int size) | 160 | static inline int ab_calc_mark_x_pos(int mark, int capacity, |
161 | int offset, int size) | ||
186 | { | 162 | { |
187 | int w = size - offset; | 163 | int w = size - offset; |
188 | return offset + ( (w * mark) / capacity ); | 164 | return offset + ( (w * mark) / capacity ); |
189 | } | 165 | } |
190 | 166 | ||
191 | static void ab_draw_veritcal_line_mark(int x, int y, int h) | 167 | static inline void ab_draw_veritcal_line_mark(struct screen * screen, |
168 | int x, int y, int h) | ||
192 | { | 169 | { |
193 | lcd_set_drawmode(DRMODE_COMPLEMENT); | 170 | screen->set_drawmode(DRMODE_COMPLEMENT); |
194 | lcd_vline(x, y, y+h-1); | 171 | screen->vline(x, y, y+h-1); |
195 | } | 172 | } |
196 | 173 | ||
197 | #define DIRECTION_RIGHT 1 | 174 | #define DIRECTION_RIGHT 1 |
198 | #define DIRECTION_LEFT -1 | 175 | #define DIRECTION_LEFT -1 |
199 | 176 | ||
200 | static void ab_draw_arrow_mark(int x, int y, int h, int direction) | 177 | static inline void ab_draw_arrow_mark(struct screen * screen, |
178 | int x, int y, int h, int direction) | ||
201 | { | 179 | { |
202 | /* draw lines in decreasing size until a height of zero is reached */ | 180 | /* draw lines in decreasing size until a height of zero is reached */ |
203 | lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | 181 | screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); |
204 | while( h > 0 ) | 182 | while( h > 0 ) |
205 | { | 183 | { |
206 | lcd_vline(x, y, y+h-1); | 184 | screen->vline(x, y, y+h-1); |
207 | h -= 2; | 185 | h -= 2; |
208 | y++; | 186 | y++; |
209 | x += direction; | 187 | x += direction; |
210 | lcd_set_drawmode(DRMODE_COMPLEMENT); | 188 | screen->set_drawmode(DRMODE_COMPLEMENT); |
211 | } | 189 | } |
212 | } | 190 | } |
213 | 191 | ||
214 | void ab_draw_markers(int capacity, int x, int y, int w, int h) | 192 | void ab_draw_markers(struct screen * screen, int capacity, |
193 | int x, int y, int h) | ||
215 | { | 194 | { |
195 | int w = screen->width; | ||
216 | /* if both markers are set, determine if they're far enough apart | 196 | /* if both markers are set, determine if they're far enough apart |
217 | to draw arrows */ | 197 | to draw arrows */ |
218 | if ( ab_A_marker_set() && ab_B_marker_set() ) | 198 | if ( ab_A_marker_set() && ab_B_marker_set() ) |
@@ -222,13 +202,13 @@ void ab_draw_markers(int capacity, int x, int y, int w, int h) | |||
222 | int arrow_width = (h+1) / 2; | 202 | int arrow_width = (h+1) / 2; |
223 | if ( (xb-xa) < (arrow_width*2) ) | 203 | if ( (xb-xa) < (arrow_width*2) ) |
224 | { | 204 | { |
225 | ab_draw_veritcal_line_mark(xa, y, h); | 205 | ab_draw_veritcal_line_mark(screen, xa, y, h); |
226 | ab_draw_veritcal_line_mark(xb, y, h); | 206 | ab_draw_veritcal_line_mark(screen, xb, y, h); |
227 | } | 207 | } |
228 | else | 208 | else |
229 | { | 209 | { |
230 | ab_draw_arrow_mark(xa, y, h, DIRECTION_RIGHT); | 210 | ab_draw_arrow_mark(screen, xa, y, h, DIRECTION_RIGHT); |
231 | ab_draw_arrow_mark(xb, y, h, DIRECTION_LEFT); | 211 | ab_draw_arrow_mark(screen, xb, y, h, DIRECTION_LEFT); |
232 | } | 212 | } |
233 | } | 213 | } |
234 | else | 214 | else |
@@ -236,12 +216,12 @@ void ab_draw_markers(int capacity, int x, int y, int w, int h) | |||
236 | if (ab_A_marker_set()) | 216 | if (ab_A_marker_set()) |
237 | { | 217 | { |
238 | int xa = ab_calc_mark_x_pos(ab_A_marker, capacity, x, w); | 218 | int xa = ab_calc_mark_x_pos(ab_A_marker, capacity, x, w); |
239 | ab_draw_arrow_mark(xa, y, h, DIRECTION_RIGHT); | 219 | ab_draw_arrow_mark(screen, xa, y, h, DIRECTION_RIGHT); |
240 | } | 220 | } |
241 | if (ab_B_marker_set()) | 221 | if (ab_B_marker_set()) |
242 | { | 222 | { |
243 | int xb = ab_calc_mark_x_pos(ab_B_marker, capacity, x, w); | 223 | int xb = ab_calc_mark_x_pos(ab_B_marker, capacity, x, w); |
244 | ab_draw_arrow_mark(xb, y, h, DIRECTION_LEFT); | 224 | ab_draw_arrow_mark(screen, xb, y, h, DIRECTION_LEFT); |
245 | } | 225 | } |
246 | } | 226 | } |
247 | } | 227 | } |