1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Ray Lambert
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 #ifdef AB_REPEAT_ENABLE
26 unsigned int ab_A_marker IDATA_ATTR
= AB_MARKER_NONE
;
27 unsigned int ab_B_marker IDATA_ATTR
= AB_MARKER_NONE
;
29 #if (CONFIG_CODEC == SWCODEC)
30 void ab_end_of_track_report(void)
32 if ( ab_A_marker_set() && ! ab_B_marker_set() )
34 ab_jump_to_A_marker();
38 static int ab_audio_event_handler(unsigned short event
, unsigned long data
)
40 int rc
= AUDIO_EVENT_RC_IGNORED
;
41 if ( ab_repeat_mode_enabled() )
45 case AUDIO_EVENT_POS_REPORT
:
47 if ( ! (audio_status() & AUDIO_STATUS_PAUSE
) &&
48 ab_reached_B_marker(data
) )
50 ab_jump_to_A_marker();
51 rc
= AUDIO_EVENT_RC_HANDLED
;
55 case AUDIO_EVENT_END_OF_TRACK
:
57 if ( ab_A_marker_set() && ! ab_B_marker_set() )
59 ab_jump_to_A_marker();
60 rc
= AUDIO_EVENT_RC_HANDLED
;
70 void ab_repeat_init(void)
72 static bool ab_initialized
= false;
73 if ( ! ab_initialized
)
75 ab_initialized
= true;
76 #if (CONFIG_CODEC != SWCODEC)
77 audio_register_event_handler(ab_audio_event_handler
,
78 AUDIO_EVENT_POS_REPORT
| AUDIO_EVENT_END_OF_TRACK
);
83 #if 0 /* Currently unused */
84 unsigned int ab_get_A_marker(void)
89 unsigned int ab_get_B_marker(void)
95 /* determines if the given song position is earlier than the A mark;
96 intended for use in handling the jump NEXT and PREV commands */
97 bool ab_before_A_marker(unsigned int song_position
)
99 return (ab_A_marker
!= AB_MARKER_NONE
)
100 && (song_position
< ab_A_marker
);
103 /* determines if the given song position is later than the A mark;
104 intended for use in handling the jump PREV command */
105 bool ab_after_A_marker(unsigned int song_position
)
107 /* following is the size of the virtual A marker; we pretend that the A marker
108 is larger than a single instant in order to give the user time to hit PREV again
109 to jump back to the start of the song; it should be large enough to allow a
110 reasonable amount of time for the typical user to react */
111 #define A_MARKER_VIRTUAL_SIZE 1000
112 return (ab_A_marker
!= AB_MARKER_NONE
)
113 && (song_position
> (ab_A_marker
+A_MARKER_VIRTUAL_SIZE
));
116 void ab_jump_to_A_marker(void)
118 #if (CONFIG_CODEC != SWCODEC)
119 bool paused
= (audio_status() & AUDIO_STATUS_PAUSE
) != 0;
123 audio_ff_rewind(ab_A_marker
);
124 #if (CONFIG_CODEC != SWCODEC)
130 void ab_reset_markers(void)
132 ab_A_marker
= AB_MARKER_NONE
;
133 ab_B_marker
= AB_MARKER_NONE
;
136 /* following is a fudge factor to help overcome the latency between
137 the time the user hears the passage they want to mark and the time
138 they actually press the button; the actual song position is adjusted
139 by this fudge factor when setting a mark */
140 #define EAR_TO_HAND_LATENCY_FUDGE 200
142 void ab_set_A_marker(unsigned int song_position
)
144 ab_A_marker
= song_position
;
145 ab_A_marker
= (ab_A_marker
>= EAR_TO_HAND_LATENCY_FUDGE
)
146 ? (ab_A_marker
- EAR_TO_HAND_LATENCY_FUDGE
) : 0;
147 /* check if markers are out of order */
148 if ( (ab_B_marker
!= AB_MARKER_NONE
) && (ab_A_marker
> ab_B_marker
) )
149 ab_B_marker
= AB_MARKER_NONE
;
152 void ab_set_B_marker(unsigned int song_position
)
154 ab_B_marker
= song_position
;
155 ab_B_marker
= (ab_B_marker
>= EAR_TO_HAND_LATENCY_FUDGE
)
156 ? (ab_B_marker
- EAR_TO_HAND_LATENCY_FUDGE
) : 0;
157 /* check if markers are out of order */
158 if ( (ab_A_marker
!= AB_MARKER_NONE
) && (ab_B_marker
< ab_A_marker
) )
159 ab_A_marker
= AB_MARKER_NONE
;
162 #ifdef HAVE_LCD_BITMAP
164 static inline int ab_calc_mark_x_pos(int mark
, int capacity
,
165 int offset
, int size
)
167 int w
= size
- offset
;
168 return offset
+ ( (w
* mark
) / capacity
);
171 static inline void ab_draw_vertical_line_mark(struct screen
* screen
,
174 screen
->set_drawmode(DRMODE_COMPLEMENT
);
175 screen
->vline(x
, y
, y
+h
-1);
178 #define DIRECTION_RIGHT 1
179 #define DIRECTION_LEFT -1
181 static inline void ab_draw_arrow_mark(struct screen
* screen
,
182 int x
, int y
, int h
, int direction
)
184 /* draw lines in decreasing size until a height of zero is reached */
185 screen
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
188 screen
->vline(x
, y
, y
+h
-1);
192 screen
->set_drawmode(DRMODE_COMPLEMENT
);
196 void ab_draw_markers(struct screen
* screen
, int capacity
,
197 int x0
, int x1
, int y
, int h
)
199 /* if both markers are set, determine if they're far enough apart
201 if ( ab_A_marker_set() && ab_B_marker_set() )
203 int xa
= ab_calc_mark_x_pos(ab_A_marker
, capacity
, x0
, x1
);
204 int xb
= ab_calc_mark_x_pos(ab_B_marker
, capacity
, x0
, x1
);
205 int arrow_width
= (h
+1) / 2;
206 if ( (xb
-xa
) < (arrow_width
*2) )
208 ab_draw_vertical_line_mark(screen
, xa
, y
, h
);
209 ab_draw_vertical_line_mark(screen
, xb
, y
, h
);
213 ab_draw_arrow_mark(screen
, xa
, y
, h
, DIRECTION_RIGHT
);
214 ab_draw_arrow_mark(screen
, xb
, y
, h
, DIRECTION_LEFT
);
219 if (ab_A_marker_set())
221 int xa
= ab_calc_mark_x_pos(ab_A_marker
, capacity
, x0
, x1
);
222 ab_draw_arrow_mark(screen
, xa
, y
, h
, DIRECTION_RIGHT
);
224 if (ab_B_marker_set())
226 int xb
= ab_calc_mark_x_pos(ab_B_marker
, capacity
, x0
, x1
);
227 ab_draw_arrow_mark(screen
, xb
, y
, h
, DIRECTION_LEFT
);
232 #endif /* HAVE_LCD_BITMAP */
234 #endif /* AB_REPEAT_ENABLE */