/* ------------------------------------------------------------------------*/ static bool play_bookmark(const char* bookmark) { #if CONFIG_CODEC == SWCODEC && defined(HAVE_PITCHCONTROL) /* preset pitch and speed to 100% in case bookmark doesn't have info */ bm.pitch = sound_get_pitch(); bm.speed = dsp_get_timestretch(); #endif if (parse_bookmark(bookmark, true, true)) { global_settings.repeat_mode = bm.repeat_mode; global_settings.playlist_shuffle = bm.shuffle; #if CONFIG_CODEC == SWCODEC && defined(HAVE_PITCHCONTROL) sound_set_pitch(bm.pitch); dsp_set_timestretch(bm.speed); #endif if (!warn_on_pl_erase()) return false; return bookmark_play(global_temp_buffer, bm.resume_index, bm.resume_time, bm.resume_offset, bm.resume_seed, global_filename); } return false; }
int gui_syncpitchscreen_run(void) { int button, i; int32_t pitch = sound_get_pitch(); int32_t semitone; int32_t new_pitch; int32_t pitch_delta; bool nudged = false; bool exit = false; /* should maybe be passed per parameter later, not needed for now */ struct viewport parent[NB_SCREENS]; struct viewport pitch_viewports[NB_SCREENS][PITCH_ITEM_COUNT]; int max_lines[NB_SCREENS]; #if CONFIG_CODEC == SWCODEC int32_t new_speed = 0, new_stretch; /* the speed variable holds the apparent speed of the playback */ int32_t speed; if (dsp_timestretch_available()) { speed = GET_SPEED(pitch, dsp_get_timestretch()); } else { speed = pitch; } /* Figure out whether to be in timestretch mode */ if (global_settings.pitch_mode_timestretch && !dsp_timestretch_available()) { global_settings.pitch_mode_timestretch = false; settings_save(); } #endif /* set the semitone index based on the current pitch */ semitone = get_semitone_from_pitch(pitch); /* initialize pitchscreen vps */ FOR_NB_SCREENS(i) { viewport_set_defaults(&parent[i], i); max_lines[i] = viewport_get_nb_lines(&parent[i]); pitchscreen_fix_viewports(&parent[i], pitch_viewports[i]); screens[i].set_viewport(&parent[i]); screens[i].clear_viewport(); /* also, draw the icons now, it's only needed once */ pitchscreen_draw_icons(&screens[i], &parent[i]); } #if CONFIG_CODEC == SWCODEC pcmbuf_set_low_latency(true); #endif while (!exit) { FOR_NB_SCREENS(i) pitchscreen_draw(&screens[i], max_lines[i], pitch_viewports[i], pitch, semitone #if CONFIG_CODEC == SWCODEC , speed #endif ); pitch_delta = 0; #if CONFIG_CODEC == SWCODEC new_speed = 0; #endif button = get_action(CONTEXT_PITCHSCREEN, HZ); #ifdef HAVE_TOUCHSCREEN if (button == ACTION_TOUCHSCREEN) { FOR_NB_SCREENS(i) button = pitchscreen_do_touchscreen(pitch_viewports[i]); } #endif switch (button) { case ACTION_PS_INC_SMALL: if(global_settings.pitch_mode_semitone) pitch_delta = SEMITONE_SMALL_DELTA; else pitch_delta = PITCH_SMALL_DELTA; break; case ACTION_PS_INC_BIG: if(global_settings.pitch_mode_semitone) pitch_delta = SEMITONE_BIG_DELTA; else pitch_delta = PITCH_BIG_DELTA; break; case ACTION_PS_DEC_SMALL: if(global_settings.pitch_mode_semitone) pitch_delta = -SEMITONE_SMALL_DELTA; else pitch_delta = -PITCH_SMALL_DELTA; break; case ACTION_PS_DEC_BIG: if(global_settings.pitch_mode_semitone) pitch_delta = -SEMITONE_BIG_DELTA; else pitch_delta = -PITCH_BIG_DELTA; break; case ACTION_PS_NUDGE_RIGHT: #if CONFIG_CODEC == SWCODEC if (!global_settings.pitch_mode_timestretch) { #endif new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false #if CONFIG_CODEC == SWCODEC , speed #endif ); nudged = (new_pitch != pitch); pitch = new_pitch; semitone = get_semitone_from_pitch(pitch); #if CONFIG_CODEC == SWCODEC speed = pitch; #endif break; #if CONFIG_CODEC == SWCODEC } else { new_speed = speed + SPEED_SMALL_DELTA; at_limit = false; } break; case ACTION_PS_FASTER: if (global_settings.pitch_mode_timestretch) { new_speed = speed + SPEED_BIG_DELTA; /* snap to whole numbers */ if(new_speed % PITCH_SPEED_PRECISION != 0) new_speed -= new_speed % PITCH_SPEED_PRECISION; at_limit = false; } break; #endif case ACTION_PS_NUDGE_RIGHTOFF: if (nudged) { pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false #if CONFIG_CODEC == SWCODEC , speed #endif ); #if CONFIG_CODEC == SWCODEC speed = pitch; #endif semitone = get_semitone_from_pitch(pitch); nudged = false; } break; case ACTION_PS_NUDGE_LEFT: #if CONFIG_CODEC == SWCODEC if (!global_settings.pitch_mode_timestretch) { #endif new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false #if CONFIG_CODEC == SWCODEC , speed #endif ); nudged = (new_pitch != pitch); pitch = new_pitch; semitone = get_semitone_from_pitch(pitch); #if CONFIG_CODEC == SWCODEC speed = pitch; #endif break; #if CONFIG_CODEC == SWCODEC } else { new_speed = speed - SPEED_SMALL_DELTA; at_limit = false; } break; case ACTION_PS_SLOWER: if (global_settings.pitch_mode_timestretch) { new_speed = speed - SPEED_BIG_DELTA; /* snap to whole numbers */ if(new_speed % PITCH_SPEED_PRECISION != 0) new_speed += PITCH_SPEED_PRECISION - speed % PITCH_SPEED_PRECISION; at_limit = false; } break; #endif case ACTION_PS_NUDGE_LEFTOFF: if (nudged) { pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false #if CONFIG_CODEC == SWCODEC , speed #endif ); #if CONFIG_CODEC == SWCODEC speed = pitch; #endif semitone = get_semitone_from_pitch(pitch); nudged = false; } break; case ACTION_PS_RESET: pitch = PITCH_SPEED_100; sound_set_pitch(pitch); #if CONFIG_CODEC == SWCODEC speed = PITCH_SPEED_100; if (dsp_timestretch_available()) { dsp_set_timestretch(PITCH_SPEED_100); at_limit = false; } #endif semitone = get_semitone_from_pitch(pitch); break; case ACTION_PS_TOGGLE_MODE: global_settings.pitch_mode_semitone = !global_settings.pitch_mode_semitone; #if CONFIG_CODEC == SWCODEC if (dsp_timestretch_available() && !global_settings.pitch_mode_semitone) { global_settings.pitch_mode_timestretch = !global_settings.pitch_mode_timestretch; if(!global_settings.pitch_mode_timestretch) { /* no longer in timestretch mode. Reset speed */ speed = pitch; dsp_set_timestretch(PITCH_SPEED_100); } } settings_save(); #endif break; case ACTION_PS_EXIT: exit = true; break; default: if (default_event_handler(button) == SYS_USB_CONNECTED) return 1; break; } if (pitch_delta) { if (global_settings.pitch_mode_semitone) { semitone = pitch_increase_semitone(pitch, semitone, pitch_delta #if CONFIG_CODEC == SWCODEC , speed #endif ); pitch = get_pitch_from_semitone(semitone); } else { pitch = pitch_increase(pitch, pitch_delta, true #if CONFIG_CODEC == SWCODEC , speed #endif ); semitone = get_semitone_from_pitch(pitch); } #if CONFIG_CODEC == SWCODEC if (global_settings.pitch_mode_timestretch) { /* do this to make sure we properly obey the stretch limits */ new_speed = speed; } else { speed = pitch; } #endif } #if CONFIG_CODEC == SWCODEC if(new_speed) { new_stretch = GET_STRETCH(pitch, new_speed); /* limit the amount of stretch */ if(new_stretch > STRETCH_MAX) { new_stretch = STRETCH_MAX; new_speed = GET_SPEED(pitch, new_stretch); } else if(new_stretch < STRETCH_MIN) { new_stretch = STRETCH_MIN; new_speed = GET_SPEED(pitch, new_stretch); } new_stretch = GET_STRETCH(pitch, new_speed); if(new_stretch >= STRETCH_MAX || new_stretch <= STRETCH_MIN) { at_limit = true; } /* set the amount of stretch */ dsp_set_timestretch(new_stretch); /* update the speed variable with the new speed */ speed = new_speed; /* Reset new_speed so we only call dsp_set_timestretch */ /* when needed */ new_speed = 0; } #endif } #if CONFIG_CODEC == SWCODEC pcmbuf_set_low_latency(false); #endif return 0; }
static int32_t pitch_increase(int32_t pitch, int32_t pitch_delta, bool allow_cutoff #if CONFIG_CODEC == SWCODEC /* need this to maintain correct pitch/speed caps */ , int32_t speed #endif ) { int32_t new_pitch; #if CONFIG_CODEC == SWCODEC int32_t new_stretch; #endif at_limit = false; if (pitch_delta < 0) { /* for large jumps, snap up to whole numbers */ if(allow_cutoff && pitch_delta <= -PITCH_SPEED_PRECISION && (pitch + pitch_delta) % PITCH_SPEED_PRECISION != 0) { pitch_delta += PITCH_SPEED_PRECISION - ((pitch + pitch_delta) % PITCH_SPEED_PRECISION); } new_pitch = pitch + pitch_delta; if (new_pitch < PITCH_MIN) { if (!allow_cutoff) { return pitch; } new_pitch = PITCH_MIN; at_limit = true; } } else if (pitch_delta > 0) { /* for large jumps, snap down to whole numbers */ if(allow_cutoff && pitch_delta >= PITCH_SPEED_PRECISION && (pitch + pitch_delta) % PITCH_SPEED_PRECISION != 0) { pitch_delta -= (pitch + pitch_delta) % PITCH_SPEED_PRECISION; } new_pitch = pitch + pitch_delta; if (new_pitch > PITCH_MAX) { if (!allow_cutoff) return pitch; new_pitch = PITCH_MAX; at_limit = true; } } else { /* pitch_delta == 0 -> no real change */ return pitch; } #if CONFIG_CODEC == SWCODEC if (dsp_timestretch_available()) { /* increase the multiple to increase precision of this calculation */ new_stretch = GET_STRETCH(new_pitch, speed); if(new_stretch < STRETCH_MIN) { /* we have to ignore allow_cutoff, because we can't have the */ /* stretch go higher than STRETCH_MAX */ new_pitch = GET_PITCH(speed, STRETCH_MIN); } else if(new_stretch > STRETCH_MAX) { /* we have to ignore allow_cutoff, because we can't have the */ /* stretch go higher than STRETCH_MAX */ new_pitch = GET_PITCH(speed, STRETCH_MAX); } if(new_stretch >= STRETCH_MAX || new_stretch <= STRETCH_MIN) { at_limit = true; } } #endif sound_set_pitch(new_pitch); return new_pitch; }
/* tuner abstraction layer: set something to the tuner */ int s1a0903x01_set(int setting, int value) { int val = 1; switch(setting) { case RADIO_SLEEP: if (!value) { /* wakeup: just unit */ fm_in1 = DEFAULT_IN1; fm_in2 = DEFAULT_IN2; fmradio_set(1, fm_in1); fmradio_set(2, fm_in2); } /* else we have no sleep mode? */ break; case RADIO_FREQUENCY: { int pll_cnt; #if CONFIG_CODEC == MAS3587F /* Shift the MAS internal clock away for certain frequencies to * avoid interference. */ int pitch = 1000; /* 4th harmonic falls in the FM frequency range */ int if_freq = 4 * mas_get_pllfreq(); /* shift the mas harmonic >= 300 kHz away using the direction * which needs less shifting. */ if (value < if_freq) { if (if_freq - value < 300000) pitch = 1003 - (if_freq - value) / 100000; } else { if (value - if_freq < 300000) pitch = 997 + (value - if_freq) / 100000; } sound_set_pitch(pitch); #endif /* We add the standard Intermediate Frequency 10.7MHz ** before calculating the divisor ** The reference frequency is set to 50kHz, and the VCO ** output is prescaled by 2. */ pll_cnt = (value + 10700000) / (PLL_FREQ_STEP/2) / 2; /* 0x100000 == FM mode ** 0x000002 == Microprocessor controlled Mute */ fm_in1 = (fm_in1 & 0xfff00007) | (pll_cnt << 3); fmradio_set(1, fm_in1); break; } case RADIO_SCAN_FREQUENCY: /* Tune in and delay */ s1a0903x01_set(RADIO_FREQUENCY, value); sleep(1); /* Start IF measurement */ fm_in1 |= 4; fmradio_set(1, fm_in1); sleep(1); val = s1a0903x01_get(RADIO_TUNED); break; case RADIO_MUTE: fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0); fmradio_set(1, fm_in1); break; case RADIO_FORCE_MONO: fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4); fmradio_set(2, fm_in2); break; /* NOTE: These were only zeroed when starting the tuner from OFF but the default values already set them to 0. */ #if 0 case S1A0903X01_IF_MEASUREMENT: fm_in1 = (fm_in1 & 0xfffffffb) | (value?4:0); fmradio_set(1, fm_in1); break; case S1A0903X01_SENSITIVITY: fm_in2 = (fm_in2 & 0xffff9fff) | ((value & 3) << 13); fmradio_set(2, fm_in2); break; #endif default: val = -1; } return val; }