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 ****************************************************************************/
26 #include <stdlib.h> /* for ABS() */
40 #include "pitchscreen.h"
42 #if CONFIG_CODEC == SWCODEC
46 #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
47 /* on both sides when drawing */
49 #define PITCH_MAX (200 * PITCH_SPEED_PRECISION)
50 #define PITCH_MIN (50 * PITCH_SPEED_PRECISION)
51 #define PITCH_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
52 #define PITCH_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
53 #define PITCH_NUDGE_DELTA (2 * PITCH_SPEED_PRECISION) /* 2% */
55 #define SPEED_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
56 #define SPEED_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
58 #define SEMITONE_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* 10 cents */
59 #define SEMITONE_BIG_DELTA PITCH_SPEED_PRECISION /* 1 semitone */
70 /* This is a table of semitone percentage values of the appropriate
71 precision (based on PITCH_SPEED_PRECISION). Note that these are
72 all constant expressions, which will be evaluated at compile time,
73 so no need to worry about how complex the expressions look.
74 That's just to get the precision right.
76 I calculated these values, starting from 50, as
80 All that math in each entry simply converts the float constant
81 to an integer equal to PITCH_SPEED_PRECISION times the float value,
82 with as little precision loss as possible (i.e. correctly rounding
85 #define TO_INT_WITH_PRECISION(x) \
86 ( (unsigned short)(((x) * PITCH_SPEED_PRECISION * 10 + 5) / 10) )
88 static const unsigned short semitone_table
[] =
90 TO_INT_WITH_PRECISION(50.00000000), /* Octave lower */
91 TO_INT_WITH_PRECISION(52.97315472),
92 TO_INT_WITH_PRECISION(56.12310242),
93 TO_INT_WITH_PRECISION(59.46035575),
94 TO_INT_WITH_PRECISION(62.99605249),
95 TO_INT_WITH_PRECISION(66.74199271),
96 TO_INT_WITH_PRECISION(70.71067812),
97 TO_INT_WITH_PRECISION(74.91535384),
98 TO_INT_WITH_PRECISION(79.37005260),
99 TO_INT_WITH_PRECISION(84.08964153),
100 TO_INT_WITH_PRECISION(89.08987181),
101 TO_INT_WITH_PRECISION(94.38743127),
102 TO_INT_WITH_PRECISION(100.0000000), /* Normal sound */
103 TO_INT_WITH_PRECISION(105.9463094),
104 TO_INT_WITH_PRECISION(112.2462048),
105 TO_INT_WITH_PRECISION(118.9207115),
106 TO_INT_WITH_PRECISION(125.9921049),
107 TO_INT_WITH_PRECISION(133.4839854),
108 TO_INT_WITH_PRECISION(141.4213562),
109 TO_INT_WITH_PRECISION(149.8307077),
110 TO_INT_WITH_PRECISION(158.7401052),
111 TO_INT_WITH_PRECISION(168.1792831),
112 TO_INT_WITH_PRECISION(178.1797436),
113 TO_INT_WITH_PRECISION(188.7748625),
114 TO_INT_WITH_PRECISION(200.0000000) /* Octave higher */
117 #define NUM_SEMITONES ((int)(sizeof(semitone_table)/sizeof(semitone_table[0])))
118 #define SEMITONE_END (NUM_SEMITONES/2)
119 #define SEMITONE_START (-SEMITONE_END)
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 static const unsigned short cent_interp
[] =
131 TO_INT_WITH_PRECISION(100.0000000),
132 TO_INT_WITH_PRECISION(101.1619440),
133 TO_INT_WITH_PRECISION(102.3373892),
134 TO_INT_WITH_PRECISION(103.5264924),
135 TO_INT_WITH_PRECISION(104.7294123),
136 /* this one's the next semitone but we have it here for convenience */
137 TO_INT_WITH_PRECISION(105.9463094),
140 /* Number of cents between entries in the cent_interp table */
141 #define CENT_INTERP_INTERVAL 20
142 #define CENT_INTERP_NUM ((int)(sizeof(cent_interp)/sizeof(cent_interp[0])))
144 /* This stores whether the pitch and speed are at their own limits */
145 /* or that of the timestretching algorithm */
146 static bool at_limit
= false;
148 static void pitchscreen_fix_viewports(struct viewport
*parent
,
149 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
])
152 font_height
= font_get(parent
->font
)->height
;
153 for (i
= 0; i
< PITCH_ITEM_COUNT
; i
++)
155 pitch_viewports
[i
] = *parent
;
156 pitch_viewports
[i
].height
= font_height
;
158 pitch_viewports
[PITCH_TOP
].y
+= ICON_BORDER
;
160 pitch_viewports
[PITCH_MID
].x
+= ICON_BORDER
;
161 pitch_viewports
[PITCH_MID
].width
= parent
->width
- ICON_BORDER
*2;
162 pitch_viewports
[PITCH_MID
].height
= parent
->height
- ICON_BORDER
*2
164 if(pitch_viewports
[PITCH_MID
].height
< font_height
* 2)
165 pitch_viewports
[PITCH_MID
].height
= font_height
* 2;
166 pitch_viewports
[PITCH_MID
].y
+= parent
->height
/ 2 -
167 pitch_viewports
[PITCH_MID
].height
/ 2;
169 pitch_viewports
[PITCH_BOTTOM
].y
+= parent
->height
- font_height
173 /* must be called before pitchscreen_draw, or within
174 * since it neither clears nor updates the display */
175 static void pitchscreen_draw_icons(struct screen
*display
,
176 struct viewport
*parent
)
178 display
->set_viewport(parent
);
179 display
->mono_bitmap(bitmap_icons_7x8
[Icon_UpArrow
],
182 display
->mono_bitmap(bitmap_icons_7x8
[Icon_DownArrow
],
183 parent
->width
/2 - 3,
184 parent
->height
- 10, 7, 8);
185 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastForward
],
187 parent
->height
/2 - 4, 7, 8);
188 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastBackward
],
190 parent
->height
/2 - 4, 7, 8);
191 display
->update_viewport();
194 static void pitchscreen_draw(struct screen
*display
, int max_lines
,
195 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
],
196 int32_t pitch
, int32_t semitone
197 #if CONFIG_CODEC == SWCODEC
205 bool show_lang_pitch
;
207 /* "Pitch up/Pitch down" - hide for a small screen */
211 display
->set_viewport(&pitch_viewports
[PITCH_TOP
]);
212 if (global_settings
.pitch_mode_semitone
)
213 ptr
= str(LANG_PITCH_UP_SEMITONE
);
215 ptr
= str(LANG_PITCH_UP
);
216 display
->getstringsize(ptr
, &w
, &h
);
217 display
->clear_viewport();
219 display
->putsxy((pitch_viewports
[PITCH_TOP
].width
/ 2) -
221 display
->update_viewport();
223 /* DOWN: Pitch Down */
224 display
->set_viewport(&pitch_viewports
[PITCH_BOTTOM
]);
225 if (global_settings
.pitch_mode_semitone
)
226 ptr
= str(LANG_PITCH_DOWN_SEMITONE
);
228 ptr
= str(LANG_PITCH_DOWN
);
229 display
->getstringsize(ptr
, &w
, &h
);
230 display
->clear_viewport();
232 display
->putsxy((pitch_viewports
[PITCH_BOTTOM
].width
/ 2) -
234 display
->update_viewport();
238 display
->set_viewport(&pitch_viewports
[PITCH_MID
]);
239 display
->clear_viewport();
242 /* Middle section upper line - hide for a small screen */
243 if ((show_lang_pitch
= (max_lines
>= 3)))
245 #if CONFIG_CODEC == SWCODEC
246 if(global_settings
.pitch_mode_timestretch
)
249 if(global_settings
.pitch_mode_semitone
)
251 snprintf(buf
, sizeof(buf
), "%s: %s%ld.%02ld", str(LANG_PITCH
),
252 semitone
>= 0 ? "+" : "-",
253 ABS(semitone
/ PITCH_SPEED_PRECISION
),
254 ABS((semitone
% PITCH_SPEED_PRECISION
) /
255 (PITCH_SPEED_PRECISION
/ 100))
260 snprintf(buf
, sizeof(buf
), "%s: %ld.%ld%%", str(LANG_PITCH
),
261 pitch
/ PITCH_SPEED_PRECISION
,
262 (pitch
% PITCH_SPEED_PRECISION
) /
263 (PITCH_SPEED_PRECISION
/ 10));
270 snprintf(buf
, sizeof(buf
), "%s:", str(LANG_PLAYBACK_RATE
));
272 display
->getstringsize(buf
, &w
, &h
);
273 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
274 (pitch_viewports
[PITCH_MID
].height
/ 2) - h
, buf
);
279 /* Middle section lower line */
281 #if CONFIG_CODEC == SWCODEC
282 if(global_settings
.pitch_mode_timestretch
)
284 snprintf(buf
, sizeof(buf
), "%s: %ld.%ld%%", str(LANG_SPEED
),
285 speed
/ PITCH_SPEED_PRECISION
,
286 (speed
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
291 if(global_settings
.pitch_mode_semitone
)
293 snprintf(buf
, sizeof(buf
), "%s%ld.%02ld",
294 semitone
>= 0 ? "+" : "-",
295 ABS(semitone
/ PITCH_SPEED_PRECISION
),
296 ABS((semitone
% PITCH_SPEED_PRECISION
) /
297 (PITCH_SPEED_PRECISION
/ 100))
302 snprintf(buf
, sizeof(buf
), "%ld.%ld%%",
303 pitch
/ PITCH_SPEED_PRECISION
,
304 (pitch
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
308 display
->getstringsize(buf
, &w
, &h
);
309 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
310 show_lang_pitch
? (pitch_viewports
[PITCH_MID
].height
/ 2) :
311 (pitch_viewports
[PITCH_MID
].height
/ 2) - (h
/ 2),
316 /* "limit" and "timestretch" labels */
321 snprintf(buf
, sizeof(buf
), "%s", str(LANG_STRETCH_LIMIT
));
322 display
->getstringsize(buf
, &w
, &h
);
323 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
324 (pitch_viewports
[PITCH_MID
].height
/ 2) + h
, buf
);
330 /* Middle section left/right labels */
331 const char *leftlabel
= "-2%";
332 const char *rightlabel
= "+2%";
333 #if CONFIG_CODEC == SWCODEC
334 if (global_settings
.pitch_mode_timestretch
)
341 /* Only display if they fit */
342 display
->getstringsize(leftlabel
, &w
, &h
);
344 display
->getstringsize(rightlabel
, &w
, &h
);
347 if (width_used
<= pitch_viewports
[PITCH_MID
].width
)
349 display
->putsxy(0, (pitch_viewports
[PITCH_MID
].height
/ 2) - (h
/ 2),
351 display
->putsxy((pitch_viewports
[PITCH_MID
].width
- w
),
352 (pitch_viewports
[PITCH_MID
].height
/ 2) - (h
/ 2),
355 display
->update_viewport();
356 display
->set_viewport(NULL
);
359 static int32_t pitch_increase(int32_t pitch
, int32_t pitch_delta
, bool allow_cutoff
360 #if CONFIG_CODEC == SWCODEC
361 /* need this to maintain correct pitch/speed caps */
367 #if CONFIG_CODEC == SWCODEC
374 /* for large jumps, snap up to whole numbers */
375 if(allow_cutoff
&& pitch_delta
<= -PITCH_SPEED_PRECISION
&&
376 (pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
!= 0)
378 pitch_delta
+= PITCH_SPEED_PRECISION
- ((pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
);
381 new_pitch
= pitch
+ pitch_delta
;
383 if (new_pitch
< PITCH_MIN
)
389 new_pitch
= PITCH_MIN
;
393 else if (pitch_delta
> 0)
395 /* for large jumps, snap down to whole numbers */
396 if(allow_cutoff
&& pitch_delta
>= PITCH_SPEED_PRECISION
&&
397 (pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
!= 0)
399 pitch_delta
-= (pitch
+ pitch_delta
) % PITCH_SPEED_PRECISION
;
402 new_pitch
= pitch
+ pitch_delta
;
404 if (new_pitch
> PITCH_MAX
)
408 new_pitch
= PITCH_MAX
;
414 /* pitch_delta == 0 -> no real change */
417 #if CONFIG_CODEC == SWCODEC
418 if (dsp_timestretch_available())
420 /* increase the multiple to increase precision of this calculation */
421 new_stretch
= GET_STRETCH(new_pitch
, speed
);
422 if(new_stretch
< STRETCH_MIN
)
424 /* we have to ignore allow_cutoff, because we can't have the */
425 /* stretch go higher than STRETCH_MAX */
426 new_pitch
= GET_PITCH(speed
, STRETCH_MIN
);
428 else if(new_stretch
> STRETCH_MAX
)
430 /* we have to ignore allow_cutoff, because we can't have the */
431 /* stretch go higher than STRETCH_MAX */
432 new_pitch
= GET_PITCH(speed
, STRETCH_MAX
);
435 if(new_stretch
>= STRETCH_MAX
||
436 new_stretch
<= STRETCH_MIN
)
443 sound_set_pitch(new_pitch
);
448 static int32_t get_semitone_from_pitch(int32_t pitch
)
451 int32_t fractional_index
= 0;
453 while(semitone
< NUM_SEMITONES
- 1 &&
454 pitch
>= semitone_table
[semitone
+ 1])
460 /* now find the fractional part */
461 while(pitch
> (cent_interp
[fractional_index
+ 1] *
462 semitone_table
[semitone
] / PITCH_SPEED_100
))
464 /* Check to make sure fractional_index isn't too big */
465 /* This should never happen. */
466 if(fractional_index
>= CENT_INTERP_NUM
- 1)
473 int32_t semitone_pitch_a
= cent_interp
[fractional_index
] *
474 semitone_table
[semitone
] /
476 int32_t semitone_pitch_b
= cent_interp
[fractional_index
+ 1] *
477 semitone_table
[semitone
] /
479 /* this will be the integer offset from the cent_interp entry */
480 int32_t semitone_frac_ofs
= (pitch
- semitone_pitch_a
) * CENT_INTERP_INTERVAL
/
481 (semitone_pitch_b
- semitone_pitch_a
);
482 semitone
= (semitone
+ SEMITONE_START
) * PITCH_SPEED_PRECISION
+
483 fractional_index
* CENT_INTERP_INTERVAL
+
489 static int32_t get_pitch_from_semitone(int32_t semitone
)
491 int32_t adjusted_semitone
= semitone
- SEMITONE_START
* PITCH_SPEED_PRECISION
;
493 /* Find the index into the semitone table */
494 int32_t semitone_index
= (adjusted_semitone
/ PITCH_SPEED_PRECISION
);
496 /* set pitch to the semitone's integer part value */
497 int32_t pitch
= semitone_table
[semitone_index
];
498 /* get the range of the cent modification for future calculation */
499 int32_t pitch_mod_a
=
500 cent_interp
[(adjusted_semitone
% PITCH_SPEED_PRECISION
) /
501 CENT_INTERP_INTERVAL
];
502 int32_t pitch_mod_b
=
503 cent_interp
[(adjusted_semitone
% PITCH_SPEED_PRECISION
) /
504 CENT_INTERP_INTERVAL
+ 1];
505 /* figure out the cent mod amount based on the semitone fractional value */
506 int32_t pitch_mod
= pitch_mod_a
+ (pitch_mod_b
- pitch_mod_a
) *
507 (adjusted_semitone
% CENT_INTERP_INTERVAL
) / CENT_INTERP_INTERVAL
;
509 /* modify pitch based on the mod amount we just calculated */
510 return (pitch
* pitch_mod
+ PITCH_SPEED_100
/ 2) / PITCH_SPEED_100
;
513 static int32_t pitch_increase_semitone(int32_t pitch
,
514 int32_t current_semitone
,
515 int32_t semitone_delta
516 #if CONFIG_CODEC == SWCODEC
521 int32_t new_semitone
= current_semitone
;
523 /* snap to the delta interval */
524 if(current_semitone
% semitone_delta
!= 0)
526 if(current_semitone
> 0 && semitone_delta
> 0)
527 new_semitone
+= semitone_delta
;
528 else if(current_semitone
< 0 && semitone_delta
< 0)
529 new_semitone
+= semitone_delta
;
531 new_semitone
-= new_semitone
% semitone_delta
;
534 new_semitone
+= semitone_delta
;
536 /* clamp the pitch so it doesn't go beyond the pitch limits */
537 if(new_semitone
< (SEMITONE_START
* PITCH_SPEED_PRECISION
))
539 new_semitone
= SEMITONE_START
* PITCH_SPEED_PRECISION
;
542 else if(new_semitone
> (SEMITONE_END
* PITCH_SPEED_PRECISION
))
544 new_semitone
= SEMITONE_END
* PITCH_SPEED_PRECISION
;
548 int32_t new_pitch
= get_pitch_from_semitone(new_semitone
);
550 #if CONFIG_CODEC == SWCODEC
551 int32_t new_stretch
= GET_STRETCH(new_pitch
, speed
);
553 /* clamp the pitch so it doesn't go beyond the stretch limits */
554 if( new_stretch
> STRETCH_MAX
)
556 new_pitch
= GET_PITCH(speed
, STRETCH_MAX
);
557 new_semitone
= get_semitone_from_pitch(new_pitch
);
560 else if (new_stretch
< STRETCH_MIN
)
562 new_pitch
= GET_PITCH(speed
, STRETCH_MIN
);
563 new_semitone
= get_semitone_from_pitch(new_pitch
);
568 pitch_increase(pitch
, new_pitch
- pitch
, false
569 #if CONFIG_CODEC == SWCODEC
580 1 if USB was connected
583 int gui_syncpitchscreen_run(void)
586 int32_t pitch
= sound_get_pitch();
593 /* should maybe be passed per parameter later, not needed for now */
594 struct viewport parent
[NB_SCREENS
];
595 struct viewport pitch_viewports
[NB_SCREENS
][PITCH_ITEM_COUNT
];
596 int max_lines
[NB_SCREENS
];
598 #if CONFIG_CODEC == SWCODEC
599 int32_t new_speed
= 0, new_stretch
;
601 /* the speed variable holds the apparent speed of the playback */
603 if (dsp_timestretch_available())
605 speed
= GET_SPEED(pitch
, dsp_get_timestretch());
612 /* Figure out whether to be in timestretch mode */
613 if (global_settings
.pitch_mode_timestretch
&& !dsp_timestretch_available())
615 global_settings
.pitch_mode_timestretch
= false;
620 /* set the semitone index based on the current pitch */
621 semitone
= get_semitone_from_pitch(pitch
);
623 /* initialize pitchscreen vps */
626 screens
[i
].clear_display();
627 viewport_set_defaults(&parent
[i
], i
);
628 max_lines
[i
] = viewport_get_nb_lines(&parent
[i
]);
629 pitchscreen_fix_viewports(&parent
[i
], pitch_viewports
[i
]);
631 /* also, draw the icons now, it's only needed once */
632 pitchscreen_draw_icons(&screens
[i
], &parent
[i
]);
634 #if CONFIG_CODEC == SWCODEC
635 pcmbuf_set_low_latency(true);
641 pitchscreen_draw(&screens
[i
], max_lines
[i
],
642 pitch_viewports
[i
], pitch
, semitone
643 #if CONFIG_CODEC == SWCODEC
648 #if CONFIG_CODEC == SWCODEC
651 button
= get_action(CONTEXT_PITCHSCREEN
, HZ
);
654 case ACTION_PS_INC_SMALL
:
655 if(global_settings
.pitch_mode_semitone
)
656 pitch_delta
= SEMITONE_SMALL_DELTA
;
658 pitch_delta
= PITCH_SMALL_DELTA
;
661 case ACTION_PS_INC_BIG
:
662 if(global_settings
.pitch_mode_semitone
)
663 pitch_delta
= SEMITONE_BIG_DELTA
;
665 pitch_delta
= PITCH_BIG_DELTA
;
668 case ACTION_PS_DEC_SMALL
:
669 if(global_settings
.pitch_mode_semitone
)
670 pitch_delta
= -SEMITONE_SMALL_DELTA
;
672 pitch_delta
= -PITCH_SMALL_DELTA
;
675 case ACTION_PS_DEC_BIG
:
676 if(global_settings
.pitch_mode_semitone
)
677 pitch_delta
= -SEMITONE_BIG_DELTA
;
679 pitch_delta
= -PITCH_BIG_DELTA
;
682 case ACTION_PS_NUDGE_RIGHT
:
683 #if CONFIG_CODEC == SWCODEC
684 if (!global_settings
.pitch_mode_timestretch
)
687 new_pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false
688 #if CONFIG_CODEC == SWCODEC
692 nudged
= (new_pitch
!= pitch
);
694 semitone
= get_semitone_from_pitch(pitch
);
695 #if CONFIG_CODEC == SWCODEC
699 #if CONFIG_CODEC == SWCODEC
703 new_speed
= speed
+ SPEED_SMALL_DELTA
;
708 case ACTION_PS_FASTER
:
709 if (global_settings
.pitch_mode_timestretch
)
711 new_speed
= speed
+ SPEED_BIG_DELTA
;
712 /* snap to whole numbers */
713 if(new_speed
% PITCH_SPEED_PRECISION
!= 0)
714 new_speed
-= new_speed
% PITCH_SPEED_PRECISION
;
720 case ACTION_PS_NUDGE_RIGHTOFF
:
723 pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false
724 #if CONFIG_CODEC == SWCODEC
728 #if CONFIG_CODEC == SWCODEC
731 semitone
= get_semitone_from_pitch(pitch
);
736 case ACTION_PS_NUDGE_LEFT
:
737 #if CONFIG_CODEC == SWCODEC
738 if (!global_settings
.pitch_mode_timestretch
)
741 new_pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false
742 #if CONFIG_CODEC == SWCODEC
746 nudged
= (new_pitch
!= pitch
);
748 semitone
= get_semitone_from_pitch(pitch
);
749 #if CONFIG_CODEC == SWCODEC
753 #if CONFIG_CODEC == SWCODEC
757 new_speed
= speed
- SPEED_SMALL_DELTA
;
762 case ACTION_PS_SLOWER
:
763 if (global_settings
.pitch_mode_timestretch
)
765 new_speed
= speed
- SPEED_BIG_DELTA
;
766 /* snap to whole numbers */
767 if(new_speed
% PITCH_SPEED_PRECISION
!= 0)
768 new_speed
+= PITCH_SPEED_PRECISION
- speed
% PITCH_SPEED_PRECISION
;
774 case ACTION_PS_NUDGE_LEFTOFF
:
777 pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false
778 #if CONFIG_CODEC == SWCODEC
782 #if CONFIG_CODEC == SWCODEC
785 semitone
= get_semitone_from_pitch(pitch
);
790 case ACTION_PS_RESET
:
791 pitch
= PITCH_SPEED_100
;
792 sound_set_pitch(pitch
);
793 #if CONFIG_CODEC == SWCODEC
794 speed
= PITCH_SPEED_100
;
795 if (dsp_timestretch_available())
797 dsp_set_timestretch(PITCH_SPEED_100
);
801 semitone
= get_semitone_from_pitch(pitch
);
804 case ACTION_PS_TOGGLE_MODE
:
805 global_settings
.pitch_mode_semitone
= !global_settings
.pitch_mode_semitone
;
806 #if CONFIG_CODEC == SWCODEC
808 if (dsp_timestretch_available() && !global_settings
.pitch_mode_semitone
)
810 global_settings
.pitch_mode_timestretch
= !global_settings
.pitch_mode_timestretch
;
811 if(!global_settings
.pitch_mode_timestretch
)
813 /* no longer in timestretch mode. Reset speed */
815 dsp_set_timestretch(PITCH_SPEED_100
);
827 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
833 if (global_settings
.pitch_mode_semitone
)
835 semitone
= pitch_increase_semitone(pitch
, semitone
, pitch_delta
836 #if CONFIG_CODEC == SWCODEC
840 pitch
= get_pitch_from_semitone(semitone
);
844 pitch
= pitch_increase(pitch
, pitch_delta
, true
845 #if CONFIG_CODEC == SWCODEC
849 semitone
= get_semitone_from_pitch(pitch
);
851 #if CONFIG_CODEC == SWCODEC
852 if (global_settings
.pitch_mode_timestretch
)
854 /* do this to make sure we properly obey the stretch limits */
864 #if CONFIG_CODEC == SWCODEC
867 new_stretch
= GET_STRETCH(pitch
, new_speed
);
869 /* limit the amount of stretch */
870 if(new_stretch
> STRETCH_MAX
)
872 new_stretch
= STRETCH_MAX
;
873 new_speed
= GET_SPEED(pitch
, new_stretch
);
875 else if(new_stretch
< STRETCH_MIN
)
877 new_stretch
= STRETCH_MIN
;
878 new_speed
= GET_SPEED(pitch
, new_stretch
);
881 new_stretch
= GET_STRETCH(pitch
, new_speed
);
882 if(new_stretch
>= STRETCH_MAX
||
883 new_stretch
<= STRETCH_MIN
)
888 /* set the amount of stretch */
889 dsp_set_timestretch(new_stretch
);
891 /* update the speed variable with the new speed */
894 /* Reset new_speed so we only call dsp_set_timestretch */
900 #if CONFIG_CODEC == SWCODEC
901 pcmbuf_set_low_latency(false);