summaryrefslogtreecommitdiff
path: root/apps/gui/pitchscreen.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gui/pitchscreen.c')
-rw-r--r--apps/gui/pitchscreen.c328
1 files changed, 232 insertions, 96 deletions
diff --git a/apps/gui/pitchscreen.c b/apps/gui/pitchscreen.c
index 485eb7861c..5072031652 100644
--- a/apps/gui/pitchscreen.c
+++ b/apps/gui/pitchscreen.c
@@ -36,12 +36,13 @@
36#include "system.h" 36#include "system.h"
37#include "misc.h" 37#include "misc.h"
38#include "pitchscreen.h" 38#include "pitchscreen.h"
39#if CONFIG_CODEC == SWCODEC
40#include "tdspeed.h"
41#endif
42
39 43
40#define PITCH_MODE_ABSOLUTE 1
41#define PITCH_MODE_SEMITONE -PITCH_MODE_ABSOLUTE
42#define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */ 44#define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
43 /* on both sides when drawing */ 45 /* on both sides when drawing */
44
45 46
46#define PITCH_MAX 2000 47#define PITCH_MAX 2000
47#define PITCH_MIN 500 48#define PITCH_MIN 500
@@ -49,8 +50,14 @@
49#define PITCH_BIG_DELTA 10 50#define PITCH_BIG_DELTA 10
50#define PITCH_NUDGE_DELTA 20 51#define PITCH_NUDGE_DELTA 20
51 52
52 53static enum
53static int pitch_mode = PITCH_MODE_ABSOLUTE; /* 1 - absolute, -1 - semitone */ 54{
55 PITCH_MODE_ABSOLUTE,
56 PITCH_MODE_SEMITONE,
57#if CONFIG_CODEC == SWCODEC
58 PITCH_MODE_TIMESTRETCH,
59#endif
60} pitch_mode = PITCH_MODE_ABSOLUTE;
54 61
55enum 62enum
56{ 63{
@@ -83,8 +90,8 @@ static void pitchscreen_fix_viewports(struct viewport *parent,
83 90
84/* must be called before pitchscreen_draw, or within 91/* must be called before pitchscreen_draw, or within
85 * since it neither clears nor updates the display */ 92 * since it neither clears nor updates the display */
86static void pitchscreen_draw_icons (struct screen *display, 93static void pitchscreen_draw_icons(struct screen *display,
87 struct viewport *parent) 94 struct viewport *parent)
88{ 95{
89 display->set_viewport(parent); 96 display->set_viewport(parent);
90 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow], 97 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
@@ -102,25 +109,29 @@ static void pitchscreen_draw_icons (struct screen *display,
102 display->update_viewport(); 109 display->update_viewport();
103} 110}
104 111
105static void pitchscreen_draw (struct screen *display, int max_lines, 112static void pitchscreen_draw(struct screen *display, int max_lines,
106 struct viewport pitch_viewports[PITCH_ITEM_COUNT], int pitch) 113 struct viewport pitch_viewports[PITCH_ITEM_COUNT],
114 int pitch
115#if CONFIG_CODEC == SWCODEC
116 ,int speed
117#endif
118 )
107{ 119{
108 unsigned char* ptr; 120 unsigned char* ptr;
109 unsigned char buf[32]; 121 char buf[32];
110 int width_val, w, h; 122 int w, h;
111 bool show_lang_pitch; 123 bool show_lang_pitch;
112 124
113 /* Hide "Pitch up/Pitch down" for a small screen */ 125 /* "Pitch up/Pitch down" - hide for a small screen */
114 if (max_lines >= 5) 126 if (max_lines >= 5)
115 { 127 {
116 /* UP: Pitch Up */ 128 /* UP: Pitch Up */
117 display->set_viewport(&pitch_viewports[PITCH_TOP]); 129 display->set_viewport(&pitch_viewports[PITCH_TOP]);
118 if (pitch_mode == PITCH_MODE_ABSOLUTE) { 130 if (pitch_mode == PITCH_MODE_SEMITONE)
119 ptr = str(LANG_PITCH_UP);
120 } else {
121 ptr = str(LANG_PITCH_UP_SEMITONE); 131 ptr = str(LANG_PITCH_UP_SEMITONE);
122 } 132 else
123 display->getstringsize(ptr,&w,&h); 133 ptr = str(LANG_PITCH_UP);
134 display->getstringsize(ptr, &w, &h);
124 display->clear_viewport(); 135 display->clear_viewport();
125 /* draw text */ 136 /* draw text */
126 display->putsxy((pitch_viewports[PITCH_TOP].width / 2) - 137 display->putsxy((pitch_viewports[PITCH_TOP].width / 2) -
@@ -129,81 +140,125 @@ static void pitchscreen_draw (struct screen *display, int max_lines,
129 140
130 /* DOWN: Pitch Down */ 141 /* DOWN: Pitch Down */
131 display->set_viewport(&pitch_viewports[PITCH_BOTTOM]); 142 display->set_viewport(&pitch_viewports[PITCH_BOTTOM]);
132 if (pitch_mode == PITCH_MODE_ABSOLUTE) { 143 if (pitch_mode == PITCH_MODE_SEMITONE)
133 ptr = str(LANG_PITCH_DOWN);
134 } else {
135 ptr = str(LANG_PITCH_DOWN_SEMITONE); 144 ptr = str(LANG_PITCH_DOWN_SEMITONE);
136 } 145 else
137 display->getstringsize(ptr,&w,&h); 146 ptr = str(LANG_PITCH_DOWN);
147 display->getstringsize(ptr, &w, &h);
138 display->clear_viewport(); 148 display->clear_viewport();
139 /* draw text */ 149 /* draw text */
140 display->putsxy((pitch_viewports[PITCH_BOTTOM].width / 2) - 150 display->putsxy((pitch_viewports[PITCH_BOTTOM].width / 2) -
141 (w / 2), 0, ptr); 151 (w / 2), 0, ptr);
142 display->update_viewport(); 152 display->update_viewport();
143 } 153 }
144 display->set_viewport(&pitch_viewports[PITCH_MID]);
145 154
146 snprintf((char *)buf, sizeof(buf), "%s", str(LANG_PITCH)); 155 /* Middle section */
147 display->getstringsize(buf,&w,&h); 156 display->set_viewport(&pitch_viewports[PITCH_MID]);
148 /* lets hide LANG_PITCH for smaller screens */
149 display->clear_viewport(); 157 display->clear_viewport();
158 int width_used = 0;
159
160 /* Middle section upper line - hide for a small screen */
150 if ((show_lang_pitch = (max_lines >= 3))) 161 if ((show_lang_pitch = (max_lines >= 3)))
162 {
163#if CONFIG_CODEC == SWCODEC
164 if (pitch_mode != PITCH_MODE_TIMESTRETCH)
165 {
166#endif
167 /* LANG_PITCH */
168 snprintf(buf, sizeof(buf), "%s", str(LANG_PITCH));
169#if CONFIG_CODEC == SWCODEC
170 }
171 else
172 {
173 /* Pitch:XXX.X% */
174 snprintf(buf, sizeof(buf), "%s:%d.%d%%", str(LANG_PITCH),
175 pitch / 10, pitch % 10);
176 }
177#endif
178 display->getstringsize(buf, &w, &h);
151 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2), 179 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
152 0, buf); 180 0, buf);
153 181 if (w > width_used)
154 /* "XXX.X%" */ 182 width_used = w;
155 snprintf((char *)buf, sizeof(buf), "%d.%d%%", 183 }
156 pitch / 10, pitch % 10 ); 184
157 display->getstringsize(buf,&width_val,&h); 185 /* Middle section lower line */
158 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (width_val / 2), 186#if CONFIG_CODEC == SWCODEC
159 (show_lang_pitch? h : h/2), buf); 187 if (pitch_mode != PITCH_MODE_TIMESTRETCH)
160 188 {
161 /* What's wider? LANG_PITCH or the value? 189#endif
162 * Only interesting if LANG_PITCH is actually drawn */ 190 /* "XXX.X%" */
163 if (show_lang_pitch && width_val > w) 191 snprintf(buf, sizeof(buf), "%d.%d%%",
164 w = width_val; 192 pitch / 10, pitch % 10);
165 193#if CONFIG_CODEC == SWCODEC
166 /* Let's treat '+' and '-' as equally wide 194 }
167 * This saves a getstringsize call 195 else
168 * Also, it wouldn't look nice if -2% shows up, but +2% not */ 196 {
169 display->getstringsize("+2%",&width_val,&h); 197 /* "Speed:XXX%" */
170 w += width_val*2; 198 snprintf(buf, sizeof(buf), "%s:%d%%", str(LANG_SPEED), speed);
171 /* hide +2%/-2% for a narrow screens */ 199 }
172 if (w <= pitch_viewports[PITCH_MID].width) 200#endif
201 display->getstringsize(buf, &w, &h);
202 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
203 (show_lang_pitch ? h : h/2), buf);
204 if (w > width_used)
205 width_used = w;
206
207 /* Middle section left/right labels */
208 const char *leftlabel = "-2%";
209 const char *rightlabel = "+2%";
210#if CONFIG_CODEC == SWCODEC
211 if (pitch_mode == PITCH_MODE_TIMESTRETCH)
212 {
213 leftlabel = "<<";
214 rightlabel = ">>";
215 }
216#endif
217
218 /* Only display if they fit */
219 display->getstringsize(leftlabel, &w, &h);
220 width_used += w;
221 display->getstringsize(rightlabel, &w, &h);
222 width_used += w;
223
224 if (width_used <= pitch_viewports[PITCH_MID].width)
173 { 225 {
174 /* RIGHT: +2% */ 226 display->putsxy(0, h / 2, leftlabel);
175 display->putsxy(pitch_viewports[PITCH_MID].width - width_val, h /2, "+2%"); 227 display->putsxy(pitch_viewports[PITCH_MID].width - w, h /2, rightlabel);
176 /* LEFT: -2% */
177 display->putsxy(0, h / 2, "-2%");
178 } 228 }
179 display->update_viewport(); 229 display->update_viewport();
180 display->set_viewport(NULL); 230 display->set_viewport(NULL);
181} 231}
182 232
183static int pitch_increase(int pitch, int delta, bool allow_cutoff) 233static int pitch_increase(int pitch, int pitch_delta, bool allow_cutoff)
184{ 234{
185 int new_pitch; 235 int new_pitch;
186 236
187 if (delta < 0) { 237 if (pitch_delta < 0)
188 if (pitch + delta >= PITCH_MIN) { 238 {
189 new_pitch = pitch + delta; 239 if (pitch + pitch_delta >= PITCH_MIN)
190 } else { 240 new_pitch = pitch + pitch_delta;
191 if (!allow_cutoff) { 241 else
242 {
243 if (!allow_cutoff)
192 return pitch; 244 return pitch;
193 }
194 new_pitch = PITCH_MIN; 245 new_pitch = PITCH_MIN;
195 } 246 }
196 } else if (delta > 0) { 247 }
197 if (pitch + delta <= PITCH_MAX) { 248 else if (pitch_delta > 0)
198 new_pitch = pitch + delta; 249 {
199 } else { 250 if (pitch + pitch_delta <= PITCH_MAX)
200 if (!allow_cutoff) { 251 new_pitch = pitch + pitch_delta;
252 else
253 {
254 if (!allow_cutoff)
201 return pitch; 255 return pitch;
202 }
203 new_pitch = PITCH_MAX; 256 new_pitch = PITCH_MAX;
204 } 257 }
205 } else { 258 }
206 /* delta == 0 -> no real change */ 259 else
260 {
261 /* pitch_delta == 0 -> no real change */
207 return pitch; 262 return pitch;
208 } 263 }
209 sound_set_pitch(new_pitch); 264 sound_set_pitch(new_pitch);
@@ -234,10 +289,13 @@ static int pitch_increase_semitone(int pitch, bool up)
234 uint32_t tmp; 289 uint32_t tmp;
235 uint32_t round_fct; /* How much to scale down at the end */ 290 uint32_t round_fct; /* How much to scale down at the end */
236 tmp = pitch; 291 tmp = pitch;
237 if (up) { 292 if (up)
293 {
238 tmp = tmp * PITCH_SEMITONE_FACTOR; 294 tmp = tmp * PITCH_SEMITONE_FACTOR;
239 round_fct = PITCH_K_FCT; 295 round_fct = PITCH_K_FCT;
240 } else { 296 }
297 else
298 {
241 tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR; 299 tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR;
242 round_fct = PITCH_N_FCT; 300 round_fct = PITCH_N_FCT;
243 } 301 }
@@ -256,7 +314,12 @@ int gui_syncpitchscreen_run(void)
256{ 314{
257 int button, i; 315 int button, i;
258 int pitch = sound_get_pitch(); 316 int pitch = sound_get_pitch();
259 int new_pitch, delta = 0; 317#if CONFIG_CODEC == SWCODEC
318 int speed = dsp_get_timestretch();
319 int maintain_speed_pitch = speed * pitch; /* speed * pitch to maintain */
320#endif
321 int new_pitch;
322 int pitch_delta = 0;
260 bool nudged = false; 323 bool nudged = false;
261 bool exit = false; 324 bool exit = false;
262 /* should maybe be passed per parameter later, not needed for now */ 325 /* should maybe be passed per parameter later, not needed for now */
@@ -283,58 +346,118 @@ int gui_syncpitchscreen_run(void)
283 { 346 {
284 FOR_NB_SCREENS(i) 347 FOR_NB_SCREENS(i)
285 pitchscreen_draw(&screens[i], max_lines[i], 348 pitchscreen_draw(&screens[i], max_lines[i],
286 pitch_viewports[i], pitch); 349 pitch_viewports[i], pitch
287 button = get_action(CONTEXT_PITCHSCREEN,HZ); 350#if CONFIG_CODEC == SWCODEC
288 switch (button) { 351 , speed
352#endif
353 );
354 button = get_action(CONTEXT_PITCHSCREEN, HZ);
355 switch (button)
356 {
289 case ACTION_PS_INC_SMALL: 357 case ACTION_PS_INC_SMALL:
290 delta = PITCH_SMALL_DELTA; 358 pitch_delta = PITCH_SMALL_DELTA;
291 break; 359 break;
292 360
293 case ACTION_PS_INC_BIG: 361 case ACTION_PS_INC_BIG:
294 delta = PITCH_BIG_DELTA; 362 pitch_delta = PITCH_BIG_DELTA;
295 break; 363 break;
296 364
297 case ACTION_PS_DEC_SMALL: 365 case ACTION_PS_DEC_SMALL:
298 delta = -PITCH_SMALL_DELTA; 366 pitch_delta = -PITCH_SMALL_DELTA;
299 break; 367 break;
300 368
301 case ACTION_PS_DEC_BIG: 369 case ACTION_PS_DEC_BIG:
302 delta = -PITCH_BIG_DELTA; 370 pitch_delta = -PITCH_BIG_DELTA;
303 break; 371 break;
304 372
305 case ACTION_PS_NUDGE_RIGHT: 373 case ACTION_PS_NUDGE_RIGHT:
306 new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false); 374#if CONFIG_CODEC == SWCODEC
307 nudged = (new_pitch != pitch); 375 if (pitch_mode != PITCH_MODE_TIMESTRETCH)
308 pitch = new_pitch; 376 {
377#endif
378 new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
379 nudged = (new_pitch != pitch);
380 pitch = new_pitch;
381 break;
382#if CONFIG_CODEC == SWCODEC
383 }
384
385 case ACTION_PS_FASTER:
386 if (pitch_mode == PITCH_MODE_TIMESTRETCH)
387 {
388 if (speed < SPEED_MAX)
389 {
390 speed++;
391 dsp_set_timestretch(speed);
392 maintain_speed_pitch = speed * pitch;
393 }
394 }
309 break; 395 break;
396#endif
310 397
311 case ACTION_PS_NUDGE_RIGHTOFF: 398 case ACTION_PS_NUDGE_RIGHTOFF:
312 if (nudged) { 399 if (nudged)
400 {
313 pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false); 401 pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
402 nudged = false;
314 } 403 }
315 nudged = false;
316 break; 404 break;
317 405
318 case ACTION_PS_NUDGE_LEFT: 406 case ACTION_PS_NUDGE_LEFT:
319 new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false); 407#if CONFIG_CODEC == SWCODEC
320 nudged = (new_pitch != pitch); 408 if (pitch_mode != PITCH_MODE_TIMESTRETCH)
321 pitch = new_pitch; 409 {
410#endif
411 new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
412 nudged = (new_pitch != pitch);
413 pitch = new_pitch;
414 break;
415#if CONFIG_CODEC == SWCODEC
416 }
417
418 case ACTION_PS_SLOWER:
419 if (pitch_mode == PITCH_MODE_TIMESTRETCH)
420 {
421 if (speed > SPEED_MIN)
422 {
423 speed--;
424 dsp_set_timestretch(speed);
425 maintain_speed_pitch = speed * pitch;
426 }
427 }
322 break; 428 break;
429#endif
323 430
324 case ACTION_PS_NUDGE_LEFTOFF: 431 case ACTION_PS_NUDGE_LEFTOFF:
325 if (nudged) { 432 if (nudged)
433 {
326 pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false); 434 pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
435 nudged = false;
327 } 436 }
328 nudged = false;
329 break; 437 break;
330 438
331 case ACTION_PS_RESET: 439 case ACTION_PS_RESET:
332 pitch = 1000; 440 pitch = 1000;
333 sound_set_pitch( pitch ); 441 sound_set_pitch(pitch);
442#if CONFIG_CODEC == SWCODEC
443 speed = 100;
444 dsp_set_timestretch(speed);
445 maintain_speed_pitch = speed * pitch;
446#endif
334 break; 447 break;
335 448
336 case ACTION_PS_TOGGLE_MODE: 449 case ACTION_PS_TOGGLE_MODE:
337 pitch_mode = -pitch_mode; 450 ++pitch_mode;
451#if CONFIG_CODEC == SWCODEC
452 if (dsp_timestretch_enabled())
453 {
454 if (pitch_mode > PITCH_MODE_TIMESTRETCH)
455 pitch_mode = PITCH_MODE_ABSOLUTE;
456 break;
457 }
458#endif
459 if (pitch_mode > PITCH_MODE_SEMITONE)
460 pitch_mode = PITCH_MODE_ABSOLUTE;
338 break; 461 break;
339 462
340 case ACTION_PS_EXIT: 463 case ACTION_PS_EXIT:
@@ -342,19 +465,32 @@ int gui_syncpitchscreen_run(void)
342 break; 465 break;
343 466
344 default: 467 default:
345 if(default_event_handler(button) == SYS_USB_CONNECTED) 468 if (default_event_handler(button) == SYS_USB_CONNECTED)
346 return 1; 469 return 1;
347 break; 470 break;
348 } 471 }
349 if(delta) 472 if (pitch_delta)
350 { 473 {
351 if (pitch_mode == PITCH_MODE_ABSOLUTE) { 474 if (pitch_mode == PITCH_MODE_SEMITONE)
352 pitch = pitch_increase(pitch, delta, true); 475 pitch = pitch_increase_semitone(pitch, pitch_delta > 0);
353 } else { 476 else
354 pitch = pitch_increase_semitone(pitch, delta > 0); 477 pitch = pitch_increase(pitch, pitch_delta, true);
478#if CONFIG_CODEC == SWCODEC
479 if (pitch_mode == PITCH_MODE_TIMESTRETCH)
480 {
481 /* Set speed to maintain time dimension */
482 /* i.e. increase pitch, slow down speed */
483 int new_speed = maintain_speed_pitch / pitch;
484 if (new_speed >= SPEED_MIN && new_speed <= SPEED_MAX)
485 {
486 speed = new_speed;
487 dsp_set_timestretch(speed);
488 }
355 } 489 }
356 490 else
357 delta = 0; 491 maintain_speed_pitch = speed * pitch;
492#endif
493 pitch_delta = 0;
358 } 494 }
359 } 495 }
360#if CONFIG_CODEC == SWCODEC 496#if CONFIG_CODEC == SWCODEC