Use TIME_BEFORE() and redo a macro slightly.
[kugel-rb.git] / apps / abrepeat.c
blob5fbd880a17775490d96d13c50941985d6379759e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include "config.h"
23 #include "abrepeat.h"
25 #ifdef AB_REPEAT_ENABLE
27 unsigned int ab_A_marker IDATA_ATTR = AB_MARKER_NONE;
28 unsigned int ab_B_marker IDATA_ATTR = AB_MARKER_NONE;
30 #if (CONFIG_CODEC == SWCODEC)
31 void ab_end_of_track_report(void)
33 if ( ab_A_marker_set() && ! ab_B_marker_set() )
35 ab_jump_to_A_marker();
38 #else
39 static int ab_audio_event_handler(unsigned short event, unsigned long data)
41 int rc = AUDIO_EVENT_RC_IGNORED;
42 if ( ab_repeat_mode_enabled() )
44 switch(event)
46 case AUDIO_EVENT_POS_REPORT:
48 if ( ! (audio_status() & AUDIO_STATUS_PAUSE) &&
49 ab_reached_B_marker(data) )
51 ab_jump_to_A_marker();
52 rc = AUDIO_EVENT_RC_HANDLED;
54 break;
56 case AUDIO_EVENT_END_OF_TRACK:
58 if ( ab_A_marker_set() && ! ab_B_marker_set() )
60 ab_jump_to_A_marker();
61 rc = AUDIO_EVENT_RC_HANDLED;
63 break;
67 return rc;
69 #endif
71 void ab_repeat_init(void)
73 static bool ab_initialized = false;
74 if ( ! ab_initialized )
76 ab_initialized = true;
77 #if (CONFIG_CODEC != SWCODEC)
78 audio_register_event_handler(ab_audio_event_handler,
79 AUDIO_EVENT_POS_REPORT | AUDIO_EVENT_END_OF_TRACK );
80 #endif
84 #if 0 /* Currently unused */
85 unsigned int ab_get_A_marker(void)
87 return ab_A_marker;
90 unsigned int ab_get_B_marker(void)
92 return ab_B_marker;
94 #endif /* if 0 */
96 /* determines if the given song position is earlier than the A mark;
97 intended for use in handling the jump NEXT and PREV commands */
98 bool ab_before_A_marker(unsigned int song_position)
100 return (ab_A_marker != AB_MARKER_NONE)
101 && (song_position < ab_A_marker);
104 /* determines if the given song position is later than the A mark;
105 intended for use in handling the jump PREV command */
106 bool ab_after_A_marker(unsigned int song_position)
108 /* following is the size of the virtual A marker; we pretend that the A marker
109 is larger than a single instant in order to give the user time to hit PREV again
110 to jump back to the start of the song; it should be large enough to allow a
111 reasonable amount of time for the typical user to react */
112 #define A_MARKER_VIRTUAL_SIZE 1000
113 return (ab_A_marker != AB_MARKER_NONE)
114 && (song_position > (ab_A_marker+A_MARKER_VIRTUAL_SIZE));
117 void ab_jump_to_A_marker(void)
119 #if (CONFIG_CODEC != SWCODEC)
120 bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0;
121 if ( ! paused )
122 audio_pause();
123 #endif
124 audio_ff_rewind(ab_A_marker);
125 #if (CONFIG_CODEC != SWCODEC)
126 if ( ! paused )
127 audio_resume();
128 #endif
131 void ab_reset_markers(void)
133 ab_A_marker = AB_MARKER_NONE;
134 ab_B_marker = AB_MARKER_NONE;
137 /* following is a fudge factor to help overcome the latency between
138 the time the user hears the passage they want to mark and the time
139 they actually press the button; the actual song position is adjusted
140 by this fudge factor when setting a mark */
141 #define EAR_TO_HAND_LATENCY_FUDGE 200
143 void ab_set_A_marker(unsigned int song_position)
145 ab_A_marker = song_position;
146 ab_A_marker = (ab_A_marker >= EAR_TO_HAND_LATENCY_FUDGE)
147 ? (ab_A_marker - EAR_TO_HAND_LATENCY_FUDGE) : 0;
148 /* check if markers are out of order */
149 if ( (ab_B_marker != AB_MARKER_NONE) && (ab_A_marker > ab_B_marker) )
150 ab_B_marker = AB_MARKER_NONE;
153 void ab_set_B_marker(unsigned int song_position)
155 ab_B_marker = song_position;
156 ab_B_marker = (ab_B_marker >= EAR_TO_HAND_LATENCY_FUDGE)
157 ? (ab_B_marker - EAR_TO_HAND_LATENCY_FUDGE) : 0;
158 /* check if markers are out of order */
159 if ( (ab_A_marker != AB_MARKER_NONE) && (ab_B_marker < ab_A_marker) )
160 ab_A_marker = AB_MARKER_NONE;
163 #ifdef HAVE_LCD_BITMAP
165 static inline int ab_calc_mark_x_pos(int mark, int capacity,
166 int offset, int size)
168 int w = size - offset;
169 return offset + ( (w * mark) / capacity );
172 static inline void ab_draw_vertical_line_mark(struct screen * screen,
173 int x, int y, int h)
175 screen->set_drawmode(DRMODE_COMPLEMENT);
176 screen->vline(x, y, y+h-1);
179 #define DIRECTION_RIGHT 1
180 #define DIRECTION_LEFT -1
182 static inline void ab_draw_arrow_mark(struct screen * screen,
183 int x, int y, int h, int direction)
185 /* draw lines in decreasing size until a height of zero is reached */
186 screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
187 while( h > 0 )
189 screen->vline(x, y, y+h-1);
190 h -= 2;
191 y++;
192 x += direction;
193 screen->set_drawmode(DRMODE_COMPLEMENT);
197 void ab_draw_markers(struct screen * screen, int capacity,
198 int x0, int x1, int y, int h)
200 /* if both markers are set, determine if they're far enough apart
201 to draw arrows */
202 if ( ab_A_marker_set() && ab_B_marker_set() )
204 int xa = ab_calc_mark_x_pos(ab_A_marker, capacity, x0, x1);
205 int xb = ab_calc_mark_x_pos(ab_B_marker, capacity, x0, x1);
206 int arrow_width = (h+1) / 2;
207 if ( (xb-xa) < (arrow_width*2) )
209 ab_draw_vertical_line_mark(screen, xa, y, h);
210 ab_draw_vertical_line_mark(screen, xb, y, h);
212 else
214 ab_draw_arrow_mark(screen, xa, y, h, DIRECTION_RIGHT);
215 ab_draw_arrow_mark(screen, xb, y, h, DIRECTION_LEFT);
218 else
220 if (ab_A_marker_set())
222 int xa = ab_calc_mark_x_pos(ab_A_marker, capacity, x0, x1);
223 ab_draw_arrow_mark(screen, xa, y, h, DIRECTION_RIGHT);
225 if (ab_B_marker_set())
227 int xb = ab_calc_mark_x_pos(ab_B_marker, capacity, x0, x1);
228 ab_draw_arrow_mark(screen, xb, y, h, DIRECTION_LEFT);
233 #endif /* HAVE_LCD_BITMAP */
235 #endif /* AB_REPEAT_ENABLE */