1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Björn Stenberg
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 ****************************************************************************/
39 #include "pitchscreen.h"
41 #if CONFIG_CODEC == SWCODEC
45 #define ABS(x) ((x) > 0 ? (x) : -(x))
47 #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
48 /* on both sides when drawing */
50 #define PITCH_MAX (200 * PITCH_SPEED_PRECISION)
51 #define PITCH_MIN (50 * PITCH_SPEED_PRECISION)
52 #define PITCH_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
53 #define PITCH_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
54 #define PITCH_NUDGE_DELTA (2 * PITCH_SPEED_PRECISION) /* 2% */
56 #define SPEED_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
57 #define SPEED_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
59 #define SEMITONE_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* 10 cents */
60 #define SEMITONE_BIG_DELTA PITCH_SPEED_PRECISION /* 1 semitone */
71 /* This is a table of semitone percentage values of the appropriate
72 precision (based on PITCH_SPEED_PRECISION). Note that these are
73 all constant expressions, which will be evaluated at compile time,
74 so no need to worry about how complex the expressions look.
75 That's just to get the precision right.
77 I calculated these values, starting from 50, as
81 All that math in each entry simply converts the float constant
82 to an integer equal to PITCH_SPEED_PRECISION times the float value,
83 with as little precision loss as possible.
85 #define SEMITONE_VALUE(x) \
86 ( (int)(((x) + 0.5 / PITCH_SPEED_PRECISION) * PITCH_SPEED_PRECISION) )
88 static const int semitone_table
[] =
91 SEMITONE_VALUE(52.97315472),
92 SEMITONE_VALUE(56.12310242),
93 SEMITONE_VALUE(59.46035575),
94 SEMITONE_VALUE(62.99605249),
95 SEMITONE_VALUE(66.74199271),
96 SEMITONE_VALUE(70.71067812),
97 SEMITONE_VALUE(74.91535384),
98 SEMITONE_VALUE(79.3700526 ),
99 SEMITONE_VALUE(84.08964153),
100 SEMITONE_VALUE(89.08987181),
101 SEMITONE_VALUE(94.38743127),
102 SEMITONE_VALUE(100 ),
103 SEMITONE_VALUE(105.9463094),
104 SEMITONE_VALUE(112.2462048),
105 SEMITONE_VALUE(118.9207115),
106 SEMITONE_VALUE(125.992105 ),
107 SEMITONE_VALUE(133.4839854),
108 SEMITONE_VALUE(141.4213562),
109 SEMITONE_VALUE(149.8307077),
110 SEMITONE_VALUE(158.7401052),
111 SEMITONE_VALUE(168.1792831),
112 SEMITONE_VALUE(178.1797436),
113 SEMITONE_VALUE(188.7748625),
117 #define NUM_SEMITONES ((int)(sizeof(semitone_table) / sizeof(int)))
118 #define SEMITONE_START -12
119 #define SEMITONE_END 12
121 /* A table of values for approximating the cent curve with
122 linear interpolation. Multipy the next lowest semitone
123 by this much to find the corresponding cent percentage.
125 These values were calculated as
126 x(n) = 100 * 2^(n * 20/1200)
129 #define CENT_INTERP(x) \
130 ( (int)(((x) + 0.5 / PITCH_SPEED_PRECISION) * PITCH_SPEED_PRECISION) )
133 static const int cent_interp
[] =
136 CENT_INTERP(101.1619440),
137 CENT_INTERP(102.3373892),
138 CENT_INTERP(103.5264924),
139 CENT_INTERP(104.7294123),
140 /* this one's the next semitone but we have it here for convenience */
141 CENT_INTERP(105.9463094),
144 /* Number of cents between entries in the cent_interp table */
145 #define CENT_INTERP_INTERVAL 20
146 #define CENT_INTERP_NUM ((int)(sizeof(cent_interp)/sizeof(int)))
148 /* This stores whether the pitch and speed are at their own limits */
149 /* or that of the timestretching algorithm */
150 static bool at_limit
= false;
152 static void pitchscreen_fix_viewports(struct viewport
*parent
,
153 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
])
156 font_height
= font_get(parent
->font
)->height
;
157 for (i
= 0; i
< PITCH_ITEM_COUNT
; i
++)
159 pitch_viewports
[i
] = *parent
;
160 pitch_viewports
[i
].height
= font_height
;
162 pitch_viewports
[PITCH_TOP
].y
+= ICON_BORDER
;
164 pitch_viewports
[PITCH_MID
].x
+= ICON_BORDER
;
165 pitch_viewports
[PITCH_MID
].width
= parent
->width
- ICON_BORDER
*2;
166 pitch_viewports
[PITCH_MID
].height
= parent
->height
- ICON_BORDER
*2
168 if(pitch_viewports
[PITCH_MID
].height
< font_height
* 2)
169 pitch_viewports
[PITCH_MID
].height
= font_height
* 2;
170 pitch_viewports
[PITCH_MID
].y
+= parent
->height
/ 2 -
171 pitch_viewports
[PITCH_MID
].height
/ 2;
173 pitch_viewports
[PITCH_BOTTOM
].y
+= parent
->height
- font_height
177 /* must be called before pitchscreen_draw, or within
178 * since it neither clears nor updates the display */
179 static void pitchscreen_draw_icons(struct screen
*display
,
180 struct viewport
*parent
)
182 display
->set_viewport(parent
);
183 display
->mono_bitmap(bitmap_icons_7x8
[Icon_UpArrow
],
186 display
->mono_bitmap(bitmap_icons_7x8
[Icon_DownArrow
],
187 parent
->width
/2 - 3,
188 parent
->height
- 10, 7, 8);
189 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastForward
],
191 parent
->height
/2 - 4, 7, 8);
192 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastBackward
],
194 parent
->height
/2 - 4, 7, 8);
195 display
->update_viewport();
198 static void pitchscreen_draw(struct screen
*display
, int max_lines
,
199 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
],
200 int32_t pitch
, int32_t semitone
201 #if CONFIG_CODEC == SWCODEC
209 bool show_lang_pitch
;
211 /* "Pitch up/Pitch down" - hide for a small screen */
215 display
->set_viewport(&pitch_viewports
[PITCH_TOP
]);
216 if (global_settings
.pitch_mode_semitone
)
217 ptr
= str(LANG_PITCH_UP_SEMITONE
);
219 ptr
= str(LANG_PITCH_UP
);
220 display
->getstringsize(ptr
, &w
, &h
);
221 display
->clear_viewport();
223 display
->putsxy((pitch_viewports
[PITCH_TOP
].width
/ 2) -
225 display
->update_viewport();
227 /* DOWN: Pitch Down */
228 display
->set_viewport(&pitch_viewports
[PITCH_BOTTOM
]);
229 if (global_settings
.pitch_mode_semitone
)
230 ptr
= str(LANG_PITCH_DOWN_SEMITONE
);
232 ptr
= str(LANG_PITCH_DOWN
);
233 display
->getstringsize(ptr
, &w
, &h
);
234 display
->clear_viewport();
236 display
->putsxy((pitch_viewports
[PITCH_BOTTOM
].width
/ 2) -
238 display
->update_viewport();
242 display
->set_viewport(&pitch_viewports
[PITCH_MID
]);
243 display
->clear_viewport();
246 /* Middle section upper line - hide for a small screen */
247 if ((show_lang_pitch
= (max_lines
>= 3)))
249 #if CONFIG_CODEC == SWCODEC
250 if(global_settings
.pitch_mode_timestretch
)
253 if(global_settings
.pitch_mode_semitone
)
255 snprintf(buf
, sizeof(buf
), "%s: %s%ld.%02ld", str(LANG_PITCH
),
256 semitone
>= 0 ? "+" : "-",
257 ABS(semitone
/ PITCH_SPEED_PRECISION
),
258 ABS((semitone
% PITCH_SPEED_PRECISION
) /
259 (PITCH_SPEED_PRECISION
/ 100))
264 snprintf(buf
, sizeof(buf
), "%s: %ld.%ld%%", str(LANG_PITCH
),
265 pitch
/ PITCH_SPEED_PRECISION
,
266 (pitch
% PITCH_SPEED_PRECISION
) /
267 (PITCH_SPEED_PRECISION
/ 10));
274 snprintf(buf
, sizeof(buf
), "%s:", str(LANG_PLAYBACK_RATE
));
276 display
->getstringsize(buf
, &w
, &h
);
277 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
278 (pitch_viewports
[PITCH_MID
].height
/ 2) - h
, buf
);
283 /* Middle section lower line */
285 #if CONFIG_CODEC == SWCODEC
286 if(global_settings
.pitch_mode_timestretch
)
288 snprintf(buf
, sizeof(buf
), "%s: %ld.%ld%%", str(LANG_SPEED
),
289 speed
/ PITCH_SPEED_PRECISION
,
290 (speed
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
295 if(global_settings
.pitch_mode_semitone
)
297 snprintf(buf
, sizeof(buf
), "%s%ld.%02ld",
298 semitone
>= 0 ? "+" : "-",
299 ABS(semitone
/ PITCH_SPEED_PRECISION
),
300 ABS((semitone
% PITCH_SPEED_PRECISION
) /
301 (PITCH_SPEED_PRECISION
/ 100))
306 snprintf(buf
, sizeof(buf
), "%ld.%ld%%",
307 pitch
/ PITCH_SPEED_PRECISION
,
308 (pitch
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
312 display
->getstringsize(buf
, &w
, &h
);
313 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
314 show_lang_pitch
? (pitch_viewports
[PITCH_MID
].height
/ 2) :
315 (pitch_viewports
[PITCH_MID
].height
/ 2) - (h
/ 2),
320 /* "limit" and "timestretch" labels */
325 snprintf(buf
, sizeof(buf
), "%s", str(LANG_STRETCH_LIMIT
));
326 display
->getstringsize(buf
, &w
, &h
);
327 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
328 (pitch_viewports
[PITCH_MID
].height
/ 2) + h
, buf
);
334 /* Middle section left/right labels */
335 const char *leftlabel
= "-2%";
336 const char *rightlabel
= "+2%";
337 #if CONFIG_CODEC == SWCODEC
338 if (global_settings
.pitch_mode_timestretch
)
345 /* Only display if they fit */
346 display
->getstringsize(leftlabel
, &w
, &h
);
348 display
->getstringsize(rightlabel
, &w
, &h
);
351 if (width_used
<= pitch_viewports
[PITCH_MID
].width
)
353 display
->putsxy(0, (pitch_viewports
[PITCH_MID
].height
/ 2) - (h
/ 2),
355 display
->putsxy((pitch_viewports
[PITCH_MID
].width
- w
),
356 (pitch_viewports
[PITCH_MID
].height
/ 2) - (h
/ 2),
359 display
->update_viewport();
360 display
->set_viewport(NULL
);
363 static int32_t pitch_increase(int32_t pitch
, int32_t pitch_delta
, bool allow_cutoff
364 #if CONFIG_CODEC == SWCODEC
365 /* need this to maintain correct pitch/speed caps */
371 #if CONFIG_CODEC == SWCODEC
378 /* for large jumps, snap up to whole numbers */
379 if(allow_cutoff
&& pitch_delta
<= -PITCH_SPEED_PRECISION
&&
380 (pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
!= 0)
382 pitch_delta
+= PITCH_SPEED_PRECISION
- ((pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
);
385 new_pitch
= pitch
+ pitch_delta
;
387 if (new_pitch
< PITCH_MIN
)
393 new_pitch
= PITCH_MIN
;
397 else if (pitch_delta
> 0)
399 /* for large jumps, snap down to whole numbers */
400 if(allow_cutoff
&& pitch_delta
>= PITCH_SPEED_PRECISION
&&
401 (pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
!= 0)
403 pitch_delta
-= (pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
;
406 new_pitch
= pitch
+ pitch_delta
;
408 if (new_pitch
> PITCH_MAX
)
412 new_pitch
= PITCH_MAX
;
418 /* pitch_delta == 0 -> no real change */
421 #if CONFIG_CODEC == SWCODEC
422 if (dsp_timestretch_available())
424 /* increase the multiple to increase precision of this calculation */
425 new_stretch
= GET_STRETCH(new_pitch
, speed
);
426 if(new_stretch
< STRETCH_MIN
)
428 /* we have to ignore allow_cutoff, because we can't have the */
429 /* stretch go higher than STRETCH_MAX */
430 new_pitch
= GET_PITCH(speed
, STRETCH_MIN
);
432 else if(new_stretch
> STRETCH_MAX
)
434 /* we have to ignore allow_cutoff, because we can't have the */
435 /* stretch go higher than STRETCH_MAX */
436 new_pitch
= GET_PITCH(speed
, STRETCH_MAX
);
439 if(new_stretch
>= STRETCH_MAX
||
440 new_stretch
<= STRETCH_MIN
)
447 sound_set_pitch(new_pitch
);
452 static int32_t get_semitone_from_pitch(int32_t pitch
)
455 int32_t fractional_index
= 0;
457 while(semitone
< NUM_SEMITONES
- 1 &&
458 pitch
>= semitone_table
[semitone
+ 1])
464 /* now find the fractional part */
465 while(pitch
> (cent_interp
[fractional_index
+ 1] *
466 semitone_table
[semitone
] / PITCH_SPEED_100
))
468 /* Check to make sure fractional_index isn't too big */
469 /* This should never happen. */
470 if(fractional_index
>= CENT_INTERP_NUM
- 1)
477 int32_t semitone_pitch_a
= cent_interp
[fractional_index
] *
478 semitone_table
[semitone
] /
480 int32_t semitone_pitch_b
= cent_interp
[fractional_index
+ 1] *
481 semitone_table
[semitone
] /
483 /* this will be the integer offset from the cent_interp entry */
484 int32_t semitone_frac_ofs
= (pitch
- semitone_pitch_a
) * CENT_INTERP_INTERVAL
/
485 (semitone_pitch_b
- semitone_pitch_a
);
486 semitone
= (semitone
+ SEMITONE_START
) * PITCH_SPEED_PRECISION
+
487 fractional_index
* CENT_INTERP_INTERVAL
+
493 static int32_t get_pitch_from_semitone(int32_t semitone
)
495 int32_t adjusted_semitone
= semitone
- SEMITONE_START
* PITCH_SPEED_PRECISION
;
497 /* Find the index into the semitone table */
498 int32_t semitone_index
= (adjusted_semitone
/ PITCH_SPEED_PRECISION
);
500 /* set pitch to the semitone's integer part value */
501 int32_t pitch
= semitone_table
[semitone_index
];
502 /* get the range of the cent modification for future calculation */
503 int32_t pitch_mod_a
=
504 cent_interp
[(adjusted_semitone
% PITCH_SPEED_PRECISION
) /
505 CENT_INTERP_INTERVAL
];
506 int32_t pitch_mod_b
=
507 cent_interp
[(adjusted_semitone
% PITCH_SPEED_PRECISION
) /
508 CENT_INTERP_INTERVAL
+ 1];
509 /* figure out the cent mod amount based on the semitone fractional value */
510 int32_t pitch_mod
= pitch_mod_a
+ (pitch_mod_b
- pitch_mod_a
) *
511 (adjusted_semitone
% CENT_INTERP_INTERVAL
) / CENT_INTERP_INTERVAL
;
513 /* modify pitch based on the mod amount we just calculated */
514 return (pitch
* pitch_mod
+ PITCH_SPEED_100
/ 2) / PITCH_SPEED_100
;
517 static int32_t pitch_increase_semitone(int32_t pitch
,
518 int32_t current_semitone
,
519 int32_t semitone_delta
520 #if CONFIG_CODEC == SWCODEC
525 int32_t new_semitone
= current_semitone
;
527 /* snap to the delta interval */
528 if(current_semitone
% semitone_delta
!= 0)
530 if(current_semitone
> 0 && semitone_delta
> 0)
531 new_semitone
+= semitone_delta
;
532 else if(current_semitone
< 0 && semitone_delta
< 0)
533 new_semitone
+= semitone_delta
;
535 new_semitone
-= new_semitone
% semitone_delta
;
538 new_semitone
+= semitone_delta
;
540 /* clamp the pitch so it doesn't go beyond the pitch limits */
541 if(new_semitone
< (SEMITONE_START
* PITCH_SPEED_PRECISION
))
543 new_semitone
= SEMITONE_START
* PITCH_SPEED_PRECISION
;
546 else if(new_semitone
> (SEMITONE_END
* PITCH_SPEED_PRECISION
))
548 new_semitone
= SEMITONE_END
* PITCH_SPEED_PRECISION
;
552 int32_t new_pitch
= get_pitch_from_semitone(new_semitone
);
554 #if CONFIG_CODEC == SWCODEC
555 int32_t new_stretch
= GET_STRETCH(new_pitch
, speed
);
557 /* clamp the pitch so it doesn't go beyond the stretch limits */
558 if( new_stretch
> STRETCH_MAX
)
560 new_pitch
= GET_PITCH(speed
, STRETCH_MAX
);
561 new_semitone
= get_semitone_from_pitch(new_pitch
);
564 else if (new_stretch
< STRETCH_MIN
)
566 new_pitch
= GET_PITCH(speed
, STRETCH_MIN
);
567 new_semitone
= get_semitone_from_pitch(new_pitch
);
572 pitch_increase(pitch
, new_pitch
- pitch
, false
573 #if CONFIG_CODEC == SWCODEC
584 1 if USB was connected
587 int gui_syncpitchscreen_run(void)
590 int32_t pitch
= sound_get_pitch();
597 /* should maybe be passed per parameter later, not needed for now */
598 struct viewport parent
[NB_SCREENS
];
599 struct viewport pitch_viewports
[NB_SCREENS
][PITCH_ITEM_COUNT
];
600 int max_lines
[NB_SCREENS
];
602 #if CONFIG_CODEC == SWCODEC
603 int32_t new_speed
= 0, new_stretch
;
605 /* the speed variable holds the apparent speed of the playback */
607 if (dsp_timestretch_available())
609 speed
= GET_SPEED(pitch
, dsp_get_timestretch());
616 /* Figure out whether to be in timestretch mode */
617 if (global_settings
.pitch_mode_timestretch
&& !dsp_timestretch_available())
619 global_settings
.pitch_mode_timestretch
= false;
624 /* set the semitone index based on the current pitch */
625 semitone
= get_semitone_from_pitch(pitch
);
627 /* initialize pitchscreen vps */
630 screens
[i
].clear_display();
631 viewport_set_defaults(&parent
[i
], i
);
632 max_lines
[i
] = viewport_get_nb_lines(&parent
[i
]);
633 pitchscreen_fix_viewports(&parent
[i
], pitch_viewports
[i
]);
635 /* also, draw the icons now, it's only needed once */
636 pitchscreen_draw_icons(&screens
[i
], &parent
[i
]);
638 #if CONFIG_CODEC == SWCODEC
639 pcmbuf_set_low_latency(true);
645 pitchscreen_draw(&screens
[i
], max_lines
[i
],
646 pitch_viewports
[i
], pitch
, semitone
647 #if CONFIG_CODEC == SWCODEC
652 #if CONFIG_CODEC == SWCODEC
655 button
= get_action(CONTEXT_PITCHSCREEN
, HZ
);
658 case ACTION_PS_INC_SMALL
:
659 if(global_settings
.pitch_mode_semitone
)
660 pitch_delta
= SEMITONE_SMALL_DELTA
;
662 pitch_delta
= PITCH_SMALL_DELTA
;
665 case ACTION_PS_INC_BIG
:
666 if(global_settings
.pitch_mode_semitone
)
667 pitch_delta
= SEMITONE_BIG_DELTA
;
669 pitch_delta
= PITCH_BIG_DELTA
;
672 case ACTION_PS_DEC_SMALL
:
673 if(global_settings
.pitch_mode_semitone
)
674 pitch_delta
= -SEMITONE_SMALL_DELTA
;
676 pitch_delta
= -PITCH_SMALL_DELTA
;
679 case ACTION_PS_DEC_BIG
:
680 if(global_settings
.pitch_mode_semitone
)
681 pitch_delta
= -SEMITONE_BIG_DELTA
;
683 pitch_delta
= -PITCH_BIG_DELTA
;
686 case ACTION_PS_NUDGE_RIGHT
:
687 #if CONFIG_CODEC == SWCODEC
688 if (!global_settings
.pitch_mode_timestretch
)
691 new_pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false
692 #if CONFIG_CODEC == SWCODEC
696 nudged
= (new_pitch
!= pitch
);
698 semitone
= get_semitone_from_pitch(pitch
);
699 #if CONFIG_CODEC == SWCODEC
703 #if CONFIG_CODEC == SWCODEC
707 new_speed
= speed
+ SPEED_SMALL_DELTA
;
712 case ACTION_PS_FASTER
:
713 if (global_settings
.pitch_mode_timestretch
)
715 new_speed
= speed
+ SPEED_BIG_DELTA
;
716 /* snap to whole numbers */
717 if(new_speed
% PITCH_SPEED_PRECISION
!= 0)
718 new_speed
-= new_speed
% PITCH_SPEED_PRECISION
;
724 case ACTION_PS_NUDGE_RIGHTOFF
:
727 pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false
728 #if CONFIG_CODEC == SWCODEC
732 #if CONFIG_CODEC == SWCODEC
735 semitone
= get_semitone_from_pitch(pitch
);
740 case ACTION_PS_NUDGE_LEFT
:
741 #if CONFIG_CODEC == SWCODEC
742 if (!global_settings
.pitch_mode_timestretch
)
745 new_pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false
746 #if CONFIG_CODEC == SWCODEC
750 nudged
= (new_pitch
!= pitch
);
752 semitone
= get_semitone_from_pitch(pitch
);
753 #if CONFIG_CODEC == SWCODEC
757 #if CONFIG_CODEC == SWCODEC
761 new_speed
= speed
- SPEED_SMALL_DELTA
;
766 case ACTION_PS_SLOWER
:
767 if (global_settings
.pitch_mode_timestretch
)
769 new_speed
= speed
- SPEED_BIG_DELTA
;
770 /* snap to whole numbers */
771 if(new_speed
% PITCH_SPEED_PRECISION
!= 0)
772 new_speed
+= PITCH_SPEED_PRECISION
- speed
% PITCH_SPEED_PRECISION
;
778 case ACTION_PS_NUDGE_LEFTOFF
:
781 pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false
782 #if CONFIG_CODEC == SWCODEC
786 #if CONFIG_CODEC == SWCODEC
789 semitone
= get_semitone_from_pitch(pitch
);
794 case ACTION_PS_RESET
:
795 pitch
= PITCH_SPEED_100
;
796 sound_set_pitch(pitch
);
797 #if CONFIG_CODEC == SWCODEC
798 speed
= PITCH_SPEED_100
;
799 if (dsp_timestretch_available())
801 dsp_set_timestretch(PITCH_SPEED_100
);
805 semitone
= get_semitone_from_pitch(pitch
);
808 case ACTION_PS_TOGGLE_MODE
:
809 global_settings
.pitch_mode_semitone
= !global_settings
.pitch_mode_semitone
;
810 #if CONFIG_CODEC == SWCODEC
812 if (dsp_timestretch_available() && !global_settings
.pitch_mode_semitone
)
814 global_settings
.pitch_mode_timestretch
= !global_settings
.pitch_mode_timestretch
;
815 if(!global_settings
.pitch_mode_timestretch
)
817 /* no longer in timestretch mode. Reset speed */
819 dsp_set_timestretch(PITCH_SPEED_100
);
831 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
837 if (global_settings
.pitch_mode_semitone
)
839 semitone
= pitch_increase_semitone(pitch
, semitone
, pitch_delta
840 #if CONFIG_CODEC == SWCODEC
844 pitch
= get_pitch_from_semitone(semitone
);
848 pitch
= pitch_increase(pitch
, pitch_delta
, true
849 #if CONFIG_CODEC == SWCODEC
853 semitone
= get_semitone_from_pitch(pitch
);
855 #if CONFIG_CODEC == SWCODEC
856 if (global_settings
.pitch_mode_timestretch
)
858 /* do this to make sure we properly obey the stretch limits */
868 #if CONFIG_CODEC == SWCODEC
871 new_stretch
= GET_STRETCH(pitch
, new_speed
);
873 /* limit the amount of stretch */
874 if(new_stretch
> STRETCH_MAX
)
876 new_stretch
= STRETCH_MAX
;
877 new_speed
= GET_SPEED(pitch
, new_stretch
);
879 else if(new_stretch
< STRETCH_MIN
)
881 new_stretch
= STRETCH_MIN
;
882 new_speed
= GET_SPEED(pitch
, new_stretch
);
885 new_stretch
= GET_STRETCH(pitch
, new_speed
);
886 if(new_stretch
>= STRETCH_MAX
||
887 new_stretch
<= STRETCH_MIN
)
892 /* set the amount of stretch */
893 dsp_set_timestretch(new_stretch
);
895 /* update the speed variable with the new speed */
898 /* Reset new_speed so we only call dsp_set_timestretch */
904 #if CONFIG_CODEC == SWCODEC
905 pcmbuf_set_low_latency(false);