mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	| @@ -9,6 +9,7 @@ import android.os.Bundle; | |||||||
| import android.util.Log; | import android.util.Log; | ||||||
| import android.view.View; | import android.view.View; | ||||||
| import android.widget.CheckBox; | import android.widget.CheckBox; | ||||||
|  | import android.widget.RelativeLayout; | ||||||
| import android.widget.SeekBar; | import android.widget.SeekBar; | ||||||
| import android.widget.TextView; | import android.widget.TextView; | ||||||
|  |  | ||||||
| @@ -37,6 +38,7 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|  |  | ||||||
|     private static final double DEFAULT_TEMPO = 1.00f; |     private static final double DEFAULT_TEMPO = 1.00f; | ||||||
|     private static final double DEFAULT_PITCH = 1.00f; |     private static final double DEFAULT_PITCH = 1.00f; | ||||||
|  |     private static final int DEFAULT_SEMITONES = 0; | ||||||
|     private static final double DEFAULT_STEP = STEP_TWENTY_FIVE_PERCENT_VALUE; |     private static final double DEFAULT_STEP = STEP_TWENTY_FIVE_PERCENT_VALUE; | ||||||
|     private static final boolean DEFAULT_SKIP_SILENCE = false; |     private static final boolean DEFAULT_SKIP_SILENCE = false; | ||||||
|  |  | ||||||
| @@ -64,9 +66,11 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|  |  | ||||||
|     private double initialTempo = DEFAULT_TEMPO; |     private double initialTempo = DEFAULT_TEMPO; | ||||||
|     private double initialPitch = DEFAULT_PITCH; |     private double initialPitch = DEFAULT_PITCH; | ||||||
|  |     private int initialSemitones = DEFAULT_SEMITONES; | ||||||
|     private boolean initialSkipSilence = DEFAULT_SKIP_SILENCE; |     private boolean initialSkipSilence = DEFAULT_SKIP_SILENCE; | ||||||
|     private double tempo = DEFAULT_TEMPO; |     private double tempo = DEFAULT_TEMPO; | ||||||
|     private double pitch = DEFAULT_PITCH; |     private double pitch = DEFAULT_PITCH; | ||||||
|  |     private int semitones = DEFAULT_SEMITONES; | ||||||
|     private double stepSize = DEFAULT_STEP; |     private double stepSize = DEFAULT_STEP; | ||||||
|  |  | ||||||
|     @Nullable |     @Nullable | ||||||
| @@ -86,9 +90,19 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|     @Nullable |     @Nullable | ||||||
|     private TextView pitchStepUpText; |     private TextView pitchStepUpText; | ||||||
|     @Nullable |     @Nullable | ||||||
|  |     private SeekBar semitoneSlider; | ||||||
|  |     @Nullable | ||||||
|  |     private TextView semitoneCurrentText; | ||||||
|  |     @Nullable | ||||||
|  |     private TextView semitoneStepDownText; | ||||||
|  |     @Nullable | ||||||
|  |     private TextView semitoneStepUpText; | ||||||
|  |     @Nullable | ||||||
|     private CheckBox unhookingCheckbox; |     private CheckBox unhookingCheckbox; | ||||||
|     @Nullable |     @Nullable | ||||||
|     private CheckBox skipSilenceCheckbox; |     private CheckBox skipSilenceCheckbox; | ||||||
|  |     @Nullable | ||||||
|  |     private CheckBox adjustBySemitonesCheckbox; | ||||||
|  |  | ||||||
|     public static PlaybackParameterDialog newInstance(final double playbackTempo, |     public static PlaybackParameterDialog newInstance(final double playbackTempo, | ||||||
|                                                       final double playbackPitch, |                                                       final double playbackPitch, | ||||||
| @@ -101,6 +115,7 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|  |  | ||||||
|         dialog.tempo = playbackTempo; |         dialog.tempo = playbackTempo; | ||||||
|         dialog.pitch = playbackPitch; |         dialog.pitch = playbackPitch; | ||||||
|  |         dialog.semitones = dialog.percentToSemitones(playbackPitch); | ||||||
|  |  | ||||||
|         dialog.initialSkipSilence = playbackSkipSilence; |         dialog.initialSkipSilence = playbackSkipSilence; | ||||||
|         return dialog; |         return dialog; | ||||||
| @@ -127,9 +142,11 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         if (savedInstanceState != null) { |         if (savedInstanceState != null) { | ||||||
|             initialTempo = savedInstanceState.getDouble(INITIAL_TEMPO_KEY, DEFAULT_TEMPO); |             initialTempo = savedInstanceState.getDouble(INITIAL_TEMPO_KEY, DEFAULT_TEMPO); | ||||||
|             initialPitch = savedInstanceState.getDouble(INITIAL_PITCH_KEY, DEFAULT_PITCH); |             initialPitch = savedInstanceState.getDouble(INITIAL_PITCH_KEY, DEFAULT_PITCH); | ||||||
|  |             initialSemitones = percentToSemitones(initialPitch); | ||||||
|  |  | ||||||
|             tempo = savedInstanceState.getDouble(TEMPO_KEY, DEFAULT_TEMPO); |             tempo = savedInstanceState.getDouble(TEMPO_KEY, DEFAULT_TEMPO); | ||||||
|             pitch = savedInstanceState.getDouble(PITCH_KEY, DEFAULT_PITCH); |             pitch = savedInstanceState.getDouble(PITCH_KEY, DEFAULT_PITCH); | ||||||
|  |             semitones = percentToSemitones(pitch); | ||||||
|             stepSize = savedInstanceState.getDouble(STEP_SIZE_KEY, DEFAULT_STEP); |             stepSize = savedInstanceState.getDouble(STEP_SIZE_KEY, DEFAULT_STEP); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -160,9 +177,11 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|                 .setView(view) |                 .setView(view) | ||||||
|                 .setCancelable(true) |                 .setCancelable(true) | ||||||
|                 .setNegativeButton(R.string.cancel, (dialogInterface, i) -> |                 .setNegativeButton(R.string.cancel, (dialogInterface, i) -> | ||||||
|                         setPlaybackParameters(initialTempo, initialPitch, initialSkipSilence)) |                         setPlaybackParameters(initialTempo, initialPitch, | ||||||
|  |                                 initialSemitones, initialSkipSilence)) | ||||||
|                 .setNeutralButton(R.string.playback_reset, (dialogInterface, i) -> |                 .setNeutralButton(R.string.playback_reset, (dialogInterface, i) -> | ||||||
|                         setPlaybackParameters(DEFAULT_TEMPO, DEFAULT_PITCH, DEFAULT_SKIP_SILENCE)) |                         setPlaybackParameters(DEFAULT_TEMPO, DEFAULT_PITCH, | ||||||
|  |                                 DEFAULT_SEMITONES, DEFAULT_SKIP_SILENCE)) | ||||||
|                 .setPositiveButton(R.string.ok, (dialogInterface, i) -> |                 .setPositiveButton(R.string.ok, (dialogInterface, i) -> | ||||||
|                         setCurrentPlaybackParameters()); |                         setCurrentPlaybackParameters()); | ||||||
|  |  | ||||||
| @@ -176,12 +195,47 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|     private void setupControlViews(@NonNull final View rootView) { |     private void setupControlViews(@NonNull final View rootView) { | ||||||
|         setupHookingControl(rootView); |         setupHookingControl(rootView); | ||||||
|         setupSkipSilenceControl(rootView); |         setupSkipSilenceControl(rootView); | ||||||
|  |         setupAdjustBySemitonesControl(rootView); | ||||||
|  |  | ||||||
|         setupTempoControl(rootView); |         setupTempoControl(rootView); | ||||||
|         setupPitchControl(rootView); |         setupPitchControl(rootView); | ||||||
|  |         setupSemitoneControl(rootView); | ||||||
|  |  | ||||||
|  |         togglePitchSliderType(rootView); | ||||||
|  |  | ||||||
|         setStepSize(stepSize); |         setStepSize(stepSize); | ||||||
|         setupStepSizeSelector(rootView); |     } | ||||||
|  |  | ||||||
|  |     private void togglePitchSliderType(@NonNull final View rootView) { | ||||||
|  |         final RelativeLayout pitchControl = rootView.findViewById(R.id.pitchControl); | ||||||
|  |         final RelativeLayout semitoneControl = rootView.findViewById(R.id.semitoneControl); | ||||||
|  |  | ||||||
|  |         final View separatorStepSizeSelector = | ||||||
|  |                 rootView.findViewById(R.id.separatorStepSizeSelector); | ||||||
|  |         final RelativeLayout.LayoutParams params = | ||||||
|  |                 (RelativeLayout.LayoutParams) separatorStepSizeSelector.getLayoutParams(); | ||||||
|  |         if (pitchControl != null && semitoneControl != null && unhookingCheckbox != null) { | ||||||
|  |             if (getCurrentAdjustBySemitones()) { | ||||||
|  |                 // replaces pitchControl slider with semitoneControl slider | ||||||
|  |                 pitchControl.setVisibility(View.GONE); | ||||||
|  |                 semitoneControl.setVisibility(View.VISIBLE); | ||||||
|  |                 params.addRule(RelativeLayout.BELOW, R.id.semitoneControl); | ||||||
|  |  | ||||||
|  |                 // forces unhook for semitones | ||||||
|  |                 unhookingCheckbox.setChecked(true); | ||||||
|  |                 unhookingCheckbox.setEnabled(false); | ||||||
|  |  | ||||||
|  |                 setupTempoStepSizeSelector(rootView); | ||||||
|  |             } else { | ||||||
|  |                 semitoneControl.setVisibility(View.GONE); | ||||||
|  |                 pitchControl.setVisibility(View.VISIBLE); | ||||||
|  |                 params.addRule(RelativeLayout.BELOW, R.id.pitchControl); | ||||||
|  |  | ||||||
|  |                 // (re)enables hooking selection | ||||||
|  |                 unhookingCheckbox.setEnabled(true); | ||||||
|  |                 setupCombinedStepSizeSelector(rootView); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void setupTempoControl(@NonNull final View rootView) { |     private void setupTempoControl(@NonNull final View rootView) { | ||||||
| @@ -234,23 +288,40 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void setupSemitoneControl(@NonNull final View rootView) { | ||||||
|  |         semitoneSlider = rootView.findViewById(R.id.semitoneSeekbar); | ||||||
|  |         semitoneCurrentText = rootView.findViewById(R.id.semitoneCurrentText); | ||||||
|  |         semitoneStepDownText = rootView.findViewById(R.id.semitoneStepDown); | ||||||
|  |         semitoneStepUpText = rootView.findViewById(R.id.semitoneStepUp); | ||||||
|  |  | ||||||
|  |         if (semitoneCurrentText != null) { | ||||||
|  |             semitoneCurrentText.setText(getSignedSemitonesString(semitones)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (semitoneSlider != null) { | ||||||
|  |             setSemitoneSlider(semitones); | ||||||
|  |             semitoneSlider.setOnSeekBarChangeListener(getOnSemitoneChangedListener()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void setupHookingControl(@NonNull final View rootView) { |     private void setupHookingControl(@NonNull final View rootView) { | ||||||
|         unhookingCheckbox = rootView.findViewById(R.id.unhookCheckbox); |         unhookingCheckbox = rootView.findViewById(R.id.unhookCheckbox); | ||||||
|         if (unhookingCheckbox != null) { |         if (unhookingCheckbox != null) { | ||||||
|             // restore whether pitch and tempo are unhooked or not |             // restores whether pitch and tempo are unhooked or not | ||||||
|             unhookingCheckbox.setChecked(PreferenceManager |             unhookingCheckbox.setChecked(PreferenceManager | ||||||
|                     .getDefaultSharedPreferences(requireContext()) |                     .getDefaultSharedPreferences(requireContext()) | ||||||
|                     .getBoolean(getString(R.string.playback_unhook_key), true)); |                     .getBoolean(getString(R.string.playback_unhook_key), true)); | ||||||
|  |  | ||||||
|             unhookingCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { |             unhookingCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { | ||||||
|                 // save whether pitch and tempo are unhooked or not |                 // saves whether pitch and tempo are unhooked or not | ||||||
|                 PreferenceManager.getDefaultSharedPreferences(requireContext()) |                 PreferenceManager.getDefaultSharedPreferences(requireContext()) | ||||||
|                         .edit() |                         .edit() | ||||||
|                         .putBoolean(getString(R.string.playback_unhook_key), isChecked) |                         .putBoolean(getString(R.string.playback_unhook_key), isChecked) | ||||||
|                         .apply(); |                         .apply(); | ||||||
|  |  | ||||||
|                 if (!isChecked) { |                 if (!isChecked) { | ||||||
|                     // when unchecked, slide back to the minimum of current tempo or pitch |                     // when unchecked, slides back to the minimum of current tempo or pitch | ||||||
|                     final double minimum = Math.min(getCurrentPitch(), getCurrentTempo()); |                     final double minimum = Math.min(getCurrentPitch(), getCurrentTempo()); | ||||||
|                     setSliders(minimum); |                     setSliders(minimum); | ||||||
|                     setCurrentPlaybackParameters(); |                     setCurrentPlaybackParameters(); | ||||||
| @@ -268,6 +339,46 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void setupAdjustBySemitonesControl(@NonNull final View rootView) { | ||||||
|  |         adjustBySemitonesCheckbox = rootView.findViewById(R.id.adjustBySemitonesCheckbox); | ||||||
|  |         if (adjustBySemitonesCheckbox != null) { | ||||||
|  |             // restores whether semitone adjustment is used or not | ||||||
|  |             adjustBySemitonesCheckbox.setChecked(PreferenceManager | ||||||
|  |                 .getDefaultSharedPreferences(requireContext()) | ||||||
|  |                 .getBoolean(getString(R.string.playback_adjust_by_semitones_key), true)); | ||||||
|  |  | ||||||
|  |             // stores whether semitone adjustment is used or not | ||||||
|  |             adjustBySemitonesCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { | ||||||
|  |                 PreferenceManager.getDefaultSharedPreferences(requireContext()) | ||||||
|  |                     .edit() | ||||||
|  |                     .putBoolean(getString(R.string.playback_adjust_by_semitones_key), isChecked) | ||||||
|  |                     .apply(); | ||||||
|  |                 togglePitchSliderType(rootView); | ||||||
|  |                 if (isChecked) { | ||||||
|  |                     setPlaybackParameters( | ||||||
|  |                             getCurrentTempo(), | ||||||
|  |                             getCurrentPitch(), | ||||||
|  |                             Integer.min(12, | ||||||
|  |                                     Integer.max(-12, percentToSemitones(getCurrentPitch()) | ||||||
|  |                             )), | ||||||
|  |                             getCurrentSkipSilence() | ||||||
|  |                     ); | ||||||
|  |                     setSemitoneSlider(Integer.min(12, | ||||||
|  |                             Integer.max(-12, percentToSemitones(getCurrentPitch())) | ||||||
|  |                     )); | ||||||
|  |                 } else { | ||||||
|  |                     setPlaybackParameters( | ||||||
|  |                             getCurrentTempo(), | ||||||
|  |                             semitonesToPercent(getCurrentSemitones()), | ||||||
|  |                             getCurrentSemitones(), | ||||||
|  |                             getCurrentSkipSilence() | ||||||
|  |                     ); | ||||||
|  |                     setPitchSlider(semitonesToPercent(getCurrentSemitones())); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void setupStepSizeSelector(@NonNull final View rootView) { |     private void setupStepSizeSelector(@NonNull final View rootView) { | ||||||
|         final TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent); |         final TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent); | ||||||
|         final TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent); |         final TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent); | ||||||
| @@ -310,6 +421,22 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void setupTempoStepSizeSelector(@NonNull final View rootView) { | ||||||
|  |         final TextView playbackStepTypeText = rootView.findViewById(R.id.playback_step_type); | ||||||
|  |         if (playbackStepTypeText != null) { | ||||||
|  |             playbackStepTypeText.setText(R.string.playback_tempo_step); | ||||||
|  |         } | ||||||
|  |         setupStepSizeSelector(rootView); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void setupCombinedStepSizeSelector(@NonNull final View rootView) { | ||||||
|  |         final TextView playbackStepTypeText = rootView.findViewById(R.id.playback_step_type); | ||||||
|  |         if (playbackStepTypeText != null) { | ||||||
|  |             playbackStepTypeText.setText(R.string.playback_step); | ||||||
|  |         } | ||||||
|  |         setupStepSizeSelector(rootView); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void setStepSize(final double stepSize) { |     private void setStepSize(final double stepSize) { | ||||||
|         this.stepSize = stepSize; |         this.stepSize = stepSize; | ||||||
|  |  | ||||||
| @@ -344,6 +471,20 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|                 setCurrentPlaybackParameters(); |                 setCurrentPlaybackParameters(); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (semitoneStepDownText != null) { | ||||||
|  |             semitoneStepDownText.setOnClickListener(view -> { | ||||||
|  |                 onSemitoneSliderUpdated(getCurrentSemitones() - 1); | ||||||
|  |                 setCurrentPlaybackParameters(); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (semitoneStepUpText != null) { | ||||||
|  |             semitoneStepUpText.setOnClickListener(view -> { | ||||||
|  |                 onSemitoneSliderUpdated(getCurrentSemitones() + 1); | ||||||
|  |                 setCurrentPlaybackParameters(); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -398,10 +539,34 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private SeekBar.OnSeekBarChangeListener getOnSemitoneChangedListener() { | ||||||
|  |         return new SeekBar.OnSeekBarChangeListener() { | ||||||
|  |             @Override | ||||||
|  |             public void onProgressChanged(final SeekBar seekBar, final int progress, | ||||||
|  |                                           final boolean fromUser) { | ||||||
|  |                 // semitone slider supplies values 0 to 24, subtraction by 12 is required | ||||||
|  |                 final int currentSemitones = progress - 12; | ||||||
|  |                 if (fromUser) { // this change is first in chain | ||||||
|  |                     onSemitoneSliderUpdated(currentSemitones); | ||||||
|  |                     // line below also saves semitones as pitch percentages | ||||||
|  |                     onPitchSliderUpdated(semitonesToPercent(currentSemitones)); | ||||||
|  |                     setCurrentPlaybackParameters(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             public void onStartTrackingTouch(final SeekBar seekBar) { | ||||||
|  |                 // Do Nothing. | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             public void onStopTrackingTouch(final SeekBar seekBar) { | ||||||
|  |                 // Do Nothing. | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void onTempoSliderUpdated(final double newTempo) { |     private void onTempoSliderUpdated(final double newTempo) { | ||||||
|         if (unhookingCheckbox == null) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if (!unhookingCheckbox.isChecked()) { |         if (!unhookingCheckbox.isChecked()) { | ||||||
|             setSliders(newTempo); |             setSliders(newTempo); | ||||||
|         } else { |         } else { | ||||||
| @@ -410,9 +575,6 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void onPitchSliderUpdated(final double newPitch) { |     private void onPitchSliderUpdated(final double newPitch) { | ||||||
|         if (unhookingCheckbox == null) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if (!unhookingCheckbox.isChecked()) { |         if (!unhookingCheckbox.isChecked()) { | ||||||
|             setSliders(newPitch); |             setSliders(newPitch); | ||||||
|         } else { |         } else { | ||||||
| @@ -420,6 +582,10 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void onSemitoneSliderUpdated(final int newSemitone) { | ||||||
|  |         setSemitoneSlider(newSemitone); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void setSliders(final double newValue) { |     private void setSliders(final double newValue) { | ||||||
|         setTempoSlider(newValue); |         setTempoSlider(newValue); | ||||||
|         setPitchSlider(newValue); |         setPitchSlider(newValue); | ||||||
| @@ -439,25 +605,49 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         pitchSlider.setProgress(strategy.progressOf(newPitch)); |         pitchSlider.setProgress(strategy.progressOf(newPitch)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void setSemitoneSlider(final int newSemitone) { | ||||||
|  |         if (semitoneSlider == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         semitoneSlider.setProgress(newSemitone + 12); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
|     // Helper |     // Helper | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     private void setCurrentPlaybackParameters() { |     private void setCurrentPlaybackParameters() { | ||||||
|         setPlaybackParameters(getCurrentTempo(), getCurrentPitch(), getCurrentSkipSilence()); |         if (getCurrentAdjustBySemitones()) { | ||||||
|  |             setPlaybackParameters( | ||||||
|  |                     getCurrentTempo(), | ||||||
|  |                     semitonesToPercent(getCurrentSemitones()), | ||||||
|  |                     getCurrentSemitones(), | ||||||
|  |                     getCurrentSkipSilence() | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             setPlaybackParameters( | ||||||
|  |                     getCurrentTempo(), | ||||||
|  |                     getCurrentPitch(), | ||||||
|  |                     percentToSemitones(getCurrentPitch()), | ||||||
|  |                     getCurrentSkipSilence() | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void setPlaybackParameters(final double newTempo, final double newPitch, |     private void setPlaybackParameters(final double newTempo, final double newPitch, | ||||||
|                                        final boolean skipSilence) { |                                        final int newSemitones, final boolean skipSilence) { | ||||||
|         if (callback != null && tempoCurrentText != null && pitchCurrentText != null) { |         if (callback != null && tempoCurrentText != null | ||||||
|  |                 && pitchCurrentText != null && semitoneCurrentText != null) { | ||||||
|             if (DEBUG) { |             if (DEBUG) { | ||||||
|                 Log.d(TAG, "Setting playback parameters to " |                 Log.d(TAG, "Setting playback parameters to " | ||||||
|                         + "tempo=[" + newTempo + "], " |                         + "tempo=[" + newTempo + "], " | ||||||
|                         + "pitch=[" + newPitch + "]"); |                         + "pitch=[" + newPitch + "], " | ||||||
|  |                         + "semitones=[" + newSemitones + "]"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             tempoCurrentText.setText(PlayerHelper.formatSpeed(newTempo)); |             tempoCurrentText.setText(PlayerHelper.formatSpeed(newTempo)); | ||||||
|             pitchCurrentText.setText(PlayerHelper.formatPitch(newPitch)); |             pitchCurrentText.setText(PlayerHelper.formatPitch(newPitch)); | ||||||
|  |             semitoneCurrentText.setText(getSignedSemitonesString(newSemitones)); | ||||||
|             callback.onPlaybackParameterChanged((float) newTempo, (float) newPitch, skipSilence); |             callback.onPlaybackParameterChanged((float) newTempo, (float) newPitch, skipSilence); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -470,6 +660,11 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         return pitchSlider == null ? pitch : strategy.valueOf(pitchSlider.getProgress()); |         return pitchSlider == null ? pitch : strategy.valueOf(pitchSlider.getProgress()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private int getCurrentSemitones() { | ||||||
|  |         // semitoneSlider is absolute, that's why - 12 | ||||||
|  |         return semitoneSlider == null ? semitones : semitoneSlider.getProgress() - 12; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private double getCurrentStepSize() { |     private double getCurrentStepSize() { | ||||||
|         return stepSize; |         return stepSize; | ||||||
|     } |     } | ||||||
| @@ -478,6 +673,10 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         return skipSilenceCheckbox != null && skipSilenceCheckbox.isChecked(); |         return skipSilenceCheckbox != null && skipSilenceCheckbox.isChecked(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private boolean getCurrentAdjustBySemitones() { | ||||||
|  |         return adjustBySemitonesCheckbox != null && adjustBySemitonesCheckbox.isChecked(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @NonNull |     @NonNull | ||||||
|     private static String getStepUpPercentString(final double percent) { |     private static String getStepUpPercentString(final double percent) { | ||||||
|         return STEP_UP_SIGN + getPercentString(percent); |         return STEP_UP_SIGN + getPercentString(percent); | ||||||
| @@ -493,8 +692,21 @@ public class PlaybackParameterDialog extends DialogFragment { | |||||||
|         return PlayerHelper.formatPitch(percent); |         return PlayerHelper.formatPitch(percent); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @NonNull | ||||||
|  |     private static String getSignedSemitonesString(final int semitones) { | ||||||
|  |         return semitones > 0 ? "+" + semitones : "" + semitones; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public interface Callback { |     public interface Callback { | ||||||
|         void onPlaybackParameterChanged(float playbackTempo, float playbackPitch, |         void onPlaybackParameterChanged(float playbackTempo, float playbackPitch, | ||||||
|                                         boolean playbackSkipSilence); |                                         boolean playbackSkipSilence); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public double semitonesToPercent(final int inSemitones) { | ||||||
|  |         return Math.pow(2, inSemitones / 12.0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public int percentToSemitones(final double inPercent) { | ||||||
|  |         return (int) Math.round(12 * Math.log(inPercent) / Math.log(2)); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -261,11 +261,115 @@ | |||||||
|                 tools:text="+5%" /> |                 tools:text="+5%" /> | ||||||
|         </RelativeLayout> |         </RelativeLayout> | ||||||
|  |  | ||||||
|  |         <RelativeLayout | ||||||
|  |             android:id="@+id/semitoneControl" | ||||||
|  |             android:layout_width="match_parent" | ||||||
|  |             android:layout_height="40dp" | ||||||
|  |             android:layout_below="@id/pitchControlText" | ||||||
|  |             android:layout_marginTop="4dp" | ||||||
|  |             android:orientation="horizontal"> | ||||||
|  |  | ||||||
|  |             <org.schabi.newpipe.views.NewPipeTextView | ||||||
|  |                 android:id="@+id/semitoneStepDown" | ||||||
|  |                 android:layout_width="24dp" | ||||||
|  |                 android:layout_height="match_parent" | ||||||
|  |                 android:layout_alignParentStart="true" | ||||||
|  |                 android:layout_alignParentLeft="true" | ||||||
|  |                 android:layout_centerVertical="true" | ||||||
|  |                 android:background="?attr/selectableItemBackground" | ||||||
|  |                 android:clickable="true" | ||||||
|  |                 android:focusable="true" | ||||||
|  |                 android:gravity="center" | ||||||
|  |                 android:text="♭" | ||||||
|  |                 android:textColor="?attr/colorAccent" | ||||||
|  |                 android:textSize="24sp" | ||||||
|  |                 android:textStyle="bold" | ||||||
|  |                 tools:ignore="HardcodedText" /> | ||||||
|  |  | ||||||
|  |             <RelativeLayout | ||||||
|  |                 android:id="@+id/semitoneDisplay" | ||||||
|  |                 android:layout_width="match_parent" | ||||||
|  |                 android:layout_height="match_parent" | ||||||
|  |                 android:layout_marginLeft="4dp" | ||||||
|  |                 android:layout_marginRight="4dp" | ||||||
|  |                 android:layout_toStartOf="@+id/semitoneStepUp" | ||||||
|  |                 android:layout_toLeftOf="@+id/semitoneStepUp" | ||||||
|  |                 android:layout_toEndOf="@+id/semitoneStepDown" | ||||||
|  |                 android:layout_toRightOf="@+id/semitoneStepDown" | ||||||
|  |                 android:orientation="horizontal"> | ||||||
|  |  | ||||||
|  |                 <org.schabi.newpipe.views.NewPipeTextView | ||||||
|  |                     android:id="@+id/semitoneMinimumText" | ||||||
|  |                     android:layout_width="wrap_content" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_alignParentStart="true" | ||||||
|  |                     android:layout_alignParentLeft="true" | ||||||
|  |                     android:layout_marginStart="4dp" | ||||||
|  |                     android:layout_marginLeft="4dp" | ||||||
|  |                     android:gravity="center" | ||||||
|  |                     android:text="-12" | ||||||
|  |                     android:textColor="?attr/colorAccent" | ||||||
|  |                     tools:ignore="HardcodedText"/> | ||||||
|  |  | ||||||
|  |                 <org.schabi.newpipe.views.NewPipeTextView | ||||||
|  |                     android:id="@+id/semitoneCurrentText" | ||||||
|  |                     android:layout_width="wrap_content" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_centerHorizontal="true" | ||||||
|  |                     android:gravity="center" | ||||||
|  |                     android:textColor="?attr/colorAccent" | ||||||
|  |                     android:textStyle="bold" | ||||||
|  |                     tools:text="0" /> | ||||||
|  |  | ||||||
|  |                 <org.schabi.newpipe.views.NewPipeTextView | ||||||
|  |                     android:id="@+id/semitoneMaximumText" | ||||||
|  |                     android:layout_width="wrap_content" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_alignParentEnd="true" | ||||||
|  |                     android:layout_alignParentRight="true" | ||||||
|  |                     android:layout_marginEnd="4dp" | ||||||
|  |                     android:layout_marginRight="4dp" | ||||||
|  |                     android:gravity="center" | ||||||
|  |                     android:text="+12" | ||||||
|  |                     android:textColor="?attr/colorAccent" | ||||||
|  |                     tools:ignore="HardcodedText" /> | ||||||
|  |  | ||||||
|  |                 <androidx.appcompat.widget.AppCompatSeekBar | ||||||
|  |                     android:id="@+id/semitoneSeekbar" | ||||||
|  |                     style="@style/Widget.AppCompat.SeekBar" | ||||||
|  |                     android:layout_width="match_parent" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_below="@+id/semitoneCurrentText" | ||||||
|  |                     android:max="24" | ||||||
|  |                     android:paddingBottom="4dp" | ||||||
|  |                     android:progress="12" /> | ||||||
|  |             </RelativeLayout> | ||||||
|  |  | ||||||
|  |             <org.schabi.newpipe.views.NewPipeTextView | ||||||
|  |                 android:id="@+id/semitoneStepUp" | ||||||
|  |                 android:layout_width="24dp" | ||||||
|  |                 android:layout_height="match_parent" | ||||||
|  |                 android:layout_alignParentEnd="true" | ||||||
|  |                 android:layout_alignParentRight="true" | ||||||
|  |                 android:layout_centerVertical="true" | ||||||
|  |                 android:layout_marginEnd="4dp" | ||||||
|  |                 android:layout_marginRight="4dp" | ||||||
|  |                 android:background="?attr/selectableItemBackground" | ||||||
|  |                 android:clickable="true" | ||||||
|  |                 android:focusable="true" | ||||||
|  |                 android:gravity="center" | ||||||
|  |                 android:text="♯" | ||||||
|  |                 android:textColor="?attr/colorAccent" | ||||||
|  |                 android:textSize="20sp" | ||||||
|  |                 android:textStyle="bold" | ||||||
|  |                 tools:ignore="HardcodedText" /> | ||||||
|  |         </RelativeLayout> | ||||||
|  |  | ||||||
|         <View |         <View | ||||||
|             android:id="@+id/separatorStepSizeSelector" |             android:id="@+id/separatorStepSizeSelector" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="1dp" |             android:layout_height="1dp" | ||||||
|             android:layout_below="@+id/pitchControl" |             android:layout_below="@+id/semitoneControl" | ||||||
|             android:layout_marginStart="12dp" |             android:layout_marginStart="12dp" | ||||||
|             android:layout_marginTop="6dp" |             android:layout_marginTop="6dp" | ||||||
|             android:layout_marginEnd="12dp" |             android:layout_marginEnd="12dp" | ||||||
| @@ -280,6 +384,7 @@ | |||||||
|             android:orientation="horizontal"> |             android:orientation="horizontal"> | ||||||
|  |  | ||||||
|             <org.schabi.newpipe.views.NewPipeTextView |             <org.schabi.newpipe.views.NewPipeTextView | ||||||
|  |                 android:id="@+id/playback_step_type" | ||||||
|                 android:layout_width="0dp" |                 android:layout_width="0dp" | ||||||
|                 android:layout_height="match_parent" |                 android:layout_height="match_parent" | ||||||
|                 android:layout_weight="1" |                 android:layout_weight="1" | ||||||
| @@ -380,6 +485,18 @@ | |||||||
|                 android:clickable="true" |                 android:clickable="true" | ||||||
|                 android:focusable="true" |                 android:focusable="true" | ||||||
|                 android:text="@string/skip_silence_checkbox" /> |                 android:text="@string/skip_silence_checkbox" /> | ||||||
|  |  | ||||||
|  |             <CheckBox | ||||||
|  |                 android:id="@+id/adjustBySemitonesCheckbox" | ||||||
|  |                 android:layout_width="match_parent" | ||||||
|  |                 android:layout_height="wrap_content" | ||||||
|  |                 android:layout_below="@id/skipSilenceCheckbox" | ||||||
|  |                 android:layout_centerHorizontal="true" | ||||||
|  |                 android:checked="false" | ||||||
|  |                 android:clickable="true" | ||||||
|  |                 android:focusable="true" | ||||||
|  |                 android:maxLines="1" | ||||||
|  |                 android:text="@string/adjust_by_semitones_checkbox" /> | ||||||
|         </LinearLayout> |         </LinearLayout> | ||||||
|  |  | ||||||
|         <!-- END HERE --> |         <!-- END HERE --> | ||||||
|   | |||||||
| @@ -238,6 +238,7 @@ | |||||||
|         <item>@string/local_search_suggestions</item> |         <item>@string/local_search_suggestions</item> | ||||||
|         <item>@string/remote_search_suggestions</item> |         <item>@string/remote_search_suggestions</item> | ||||||
|     </string-array> |     </string-array> | ||||||
|  |     <string name="playback_adjust_by_semitones_key">playback_adjust_by_semitones_key</string> | ||||||
|     <string name="show_play_with_kodi_key">show_play_with_kodi</string> |     <string name="show_play_with_kodi_key">show_play_with_kodi</string> | ||||||
|     <string name="show_comments_key">show_comments</string> |     <string name="show_comments_key">show_comments</string> | ||||||
|     <string name="show_next_video_key">show_next_video</string> |     <string name="show_next_video_key">show_next_video</string> | ||||||
|   | |||||||
| @@ -486,7 +486,9 @@ | |||||||
|     <string name="playback_pitch">Pitch</string> |     <string name="playback_pitch">Pitch</string> | ||||||
|     <string name="unhook_checkbox">Unhook (may cause distortion)</string> |     <string name="unhook_checkbox">Unhook (may cause distortion)</string> | ||||||
|     <string name="skip_silence_checkbox">Fast-forward during silence</string> |     <string name="skip_silence_checkbox">Fast-forward during silence</string> | ||||||
|  |     <string name="adjust_by_semitones_checkbox">Adjust pitch by musical semitones</string> | ||||||
|     <string name="playback_step">Step</string> |     <string name="playback_step">Step</string> | ||||||
|  |     <string name="playback_tempo_step">Tempo step</string> | ||||||
|     <string name="playback_reset">Reset</string> |     <string name="playback_reset">Reset</string> | ||||||
|     <!-- GDPR dialog --> |     <!-- GDPR dialog --> | ||||||
|     <string name="start_accept_privacy_policy">In order to comply with the European General Data Protection Regulation (GDPR), we hereby draw your attention to NewPipe\'s privacy policy. Please read it carefully. |     <string name="start_accept_privacy_policy">In order to comply with the European General Data Protection Regulation (GDPR), we hereby draw your attention to NewPipe\'s privacy policy. Please read it carefully. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox