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 if (i
== PITCH_TOP
|| i
== PITCH_BOTTOM
)
159 pitch_viewports
[i
].flags
|= VP_FLAG_ALIGN_CENTER
;
161 pitch_viewports
[PITCH_TOP
].y
+= ICON_BORDER
;
163 pitch_viewports
[PITCH_MID
].x
+= ICON_BORDER
;
164 pitch_viewports
[PITCH_MID
].width
= parent
->width
- ICON_BORDER
*2;
165 pitch_viewports
[PITCH_MID
].height
= parent
->height
- ICON_BORDER
*2
167 if(pitch_viewports
[PITCH_MID
].height
< font_height
* 2)
168 pitch_viewports
[PITCH_MID
].height
= font_height
* 2;
169 pitch_viewports
[PITCH_MID
].y
+= parent
->height
/ 2 -
170 pitch_viewports
[PITCH_MID
].height
/ 2;
172 pitch_viewports
[PITCH_BOTTOM
].y
+= parent
->height
- font_height
176 /* must be called before pitchscreen_draw, or within
177 * since it neither clears nor updates the display */
178 static void pitchscreen_draw_icons(struct screen
*display
,
179 struct viewport
*parent
)
181 display
->set_viewport(parent
);
182 display
->mono_bitmap(bitmap_icons_7x8
[Icon_UpArrow
],
185 display
->mono_bitmap(bitmap_icons_7x8
[Icon_DownArrow
],
186 parent
->width
/2 - 3,
187 parent
->height
- 10, 7, 8);
188 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastForward
],
190 parent
->height
/2 - 4, 7, 8);
191 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastBackward
],
193 parent
->height
/2 - 4, 7, 8);
194 display
->update_viewport();
197 static void pitchscreen_draw(struct screen
*display
, int max_lines
,
198 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
],
199 int32_t pitch
, int32_t semitone
200 #if CONFIG_CODEC == SWCODEC
208 bool show_lang_pitch
;
210 /* "Pitch up/Pitch down" - hide for a small screen,
211 * the text is drawn centered automatically */
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
->clear_viewport();
222 display
->putsxy(0, 0, ptr
);
223 display
->update_viewport();
225 /* DOWN: Pitch Down */
226 display
->set_viewport(&pitch_viewports
[PITCH_BOTTOM
]);
227 if (global_settings
.pitch_mode_semitone
)
228 ptr
= str(LANG_PITCH_DOWN_SEMITONE
);
230 ptr
= str(LANG_PITCH_DOWN
);
231 display
->clear_viewport();
233 display
->putsxy(0, 0, ptr
);
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 const char * const p
= str(LANG_STRETCH_LIMIT
);
322 display
->getstringsize(p
, &w
, &h
);
323 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
324 (pitch_viewports
[PITCH_MID
].height
/ 2) + h
, p
);
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 viewport_set_defaults(&parent
[i
], i
);
627 max_lines
[i
] = viewport_get_nb_lines(&parent
[i
]);
628 pitchscreen_fix_viewports(&parent
[i
], pitch_viewports
[i
]);
629 screens
[i
].set_viewport(&parent
[i
]);
630 screens
[i
].clear_viewport();
632 /* also, draw the icons now, it's only needed once */
633 pitchscreen_draw_icons(&screens
[i
], &parent
[i
]);
635 #if CONFIG_CODEC == SWCODEC
636 pcmbuf_set_low_latency(true);
642 pitchscreen_draw(&screens
[i
], max_lines
[i
],
643 pitch_viewports
[i
], pitch
, semitone
644 #if CONFIG_CODEC == SWCODEC
649 #if CONFIG_CODEC == SWCODEC
652 button
= get_action(CONTEXT_PITCHSCREEN
, HZ
);
655 case ACTION_PS_INC_SMALL
:
656 if(global_settings
.pitch_mode_semitone
)
657 pitch_delta
= SEMITONE_SMALL_DELTA
;
659 pitch_delta
= PITCH_SMALL_DELTA
;
662 case ACTION_PS_INC_BIG
:
663 if(global_settings
.pitch_mode_semitone
)
664 pitch_delta
= SEMITONE_BIG_DELTA
;
666 pitch_delta
= PITCH_BIG_DELTA
;
669 case ACTION_PS_DEC_SMALL
:
670 if(global_settings
.pitch_mode_semitone
)
671 pitch_delta
= -SEMITONE_SMALL_DELTA
;
673 pitch_delta
= -PITCH_SMALL_DELTA
;
676 case ACTION_PS_DEC_BIG
:
677 if(global_settings
.pitch_mode_semitone
)
678 pitch_delta
= -SEMITONE_BIG_DELTA
;
680 pitch_delta
= -PITCH_BIG_DELTA
;
683 case ACTION_PS_NUDGE_RIGHT
:
684 #if CONFIG_CODEC == SWCODEC
685 if (!global_settings
.pitch_mode_timestretch
)
688 new_pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false
689 #if CONFIG_CODEC == SWCODEC
693 nudged
= (new_pitch
!= pitch
);
695 semitone
= get_semitone_from_pitch(pitch
);
696 #if CONFIG_CODEC == SWCODEC
700 #if CONFIG_CODEC == SWCODEC
704 new_speed
= speed
+ SPEED_SMALL_DELTA
;
709 case ACTION_PS_FASTER
:
710 if (global_settings
.pitch_mode_timestretch
)
712 new_speed
= speed
+ SPEED_BIG_DELTA
;
713 /* snap to whole numbers */
714 if(new_speed
% PITCH_SPEED_PRECISION
!= 0)
715 new_speed
-= new_speed
% PITCH_SPEED_PRECISION
;
721 case ACTION_PS_NUDGE_RIGHTOFF
:
724 pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false
725 #if CONFIG_CODEC == SWCODEC
729 #if CONFIG_CODEC == SWCODEC
732 semitone
= get_semitone_from_pitch(pitch
);
737 case ACTION_PS_NUDGE_LEFT
:
738 #if CONFIG_CODEC == SWCODEC
739 if (!global_settings
.pitch_mode_timestretch
)
742 new_pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false
743 #if CONFIG_CODEC == SWCODEC
747 nudged
= (new_pitch
!= pitch
);
749 semitone
= get_semitone_from_pitch(pitch
);
750 #if CONFIG_CODEC == SWCODEC
754 #if CONFIG_CODEC == SWCODEC
758 new_speed
= speed
- SPEED_SMALL_DELTA
;
763 case ACTION_PS_SLOWER
:
764 if (global_settings
.pitch_mode_timestretch
)
766 new_speed
= speed
- SPEED_BIG_DELTA
;
767 /* snap to whole numbers */
768 if(new_speed
% PITCH_SPEED_PRECISION
!= 0)
769 new_speed
+= PITCH_SPEED_PRECISION
- speed
% PITCH_SPEED_PRECISION
;
775 case ACTION_PS_NUDGE_LEFTOFF
:
778 pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false
779 #if CONFIG_CODEC == SWCODEC
783 #if CONFIG_CODEC == SWCODEC
786 semitone
= get_semitone_from_pitch(pitch
);
791 case ACTION_PS_RESET
:
792 pitch
= PITCH_SPEED_100
;
793 sound_set_pitch(pitch
);
794 #if CONFIG_CODEC == SWCODEC
795 speed
= PITCH_SPEED_100
;
796 if (dsp_timestretch_available())
798 dsp_set_timestretch(PITCH_SPEED_100
);
802 semitone
= get_semitone_from_pitch(pitch
);
805 case ACTION_PS_TOGGLE_MODE
:
806 global_settings
.pitch_mode_semitone
= !global_settings
.pitch_mode_semitone
;
807 #if CONFIG_CODEC == SWCODEC
809 if (dsp_timestretch_available() && !global_settings
.pitch_mode_semitone
)
811 global_settings
.pitch_mode_timestretch
= !global_settings
.pitch_mode_timestretch
;
812 if(!global_settings
.pitch_mode_timestretch
)
814 /* no longer in timestretch mode. Reset speed */
816 dsp_set_timestretch(PITCH_SPEED_100
);
828 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
834 if (global_settings
.pitch_mode_semitone
)
836 semitone
= pitch_increase_semitone(pitch
, semitone
, pitch_delta
837 #if CONFIG_CODEC == SWCODEC
841 pitch
= get_pitch_from_semitone(semitone
);
845 pitch
= pitch_increase(pitch
, pitch_delta
, true
846 #if CONFIG_CODEC == SWCODEC
850 semitone
= get_semitone_from_pitch(pitch
);
852 #if CONFIG_CODEC == SWCODEC
853 if (global_settings
.pitch_mode_timestretch
)
855 /* do this to make sure we properly obey the stretch limits */
865 #if CONFIG_CODEC == SWCODEC
868 new_stretch
= GET_STRETCH(pitch
, new_speed
);
870 /* limit the amount of stretch */
871 if(new_stretch
> STRETCH_MAX
)
873 new_stretch
= STRETCH_MAX
;
874 new_speed
= GET_SPEED(pitch
, new_stretch
);
876 else if(new_stretch
< STRETCH_MIN
)
878 new_stretch
= STRETCH_MIN
;
879 new_speed
= GET_SPEED(pitch
, new_stretch
);
882 new_stretch
= GET_STRETCH(pitch
, new_speed
);
883 if(new_stretch
>= STRETCH_MAX
||
884 new_stretch
<= STRETCH_MIN
)
889 /* set the amount of stretch */
890 dsp_set_timestretch(new_stretch
);
892 /* update the speed variable with the new speed */
895 /* Reset new_speed so we only call dsp_set_timestretch */
901 #if CONFIG_CODEC == SWCODEC
902 pcmbuf_set_low_latency(false);