mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-09 17:00:32 +00:00
commit
3f7ba2e3d1
@ -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 void onTempoSliderUpdated(final double newTempo) {
|
private SeekBar.OnSeekBarChangeListener getOnSemitoneChangedListener() {
|
||||||
if (unhookingCheckbox == null) {
|
return new SeekBar.OnSeekBarChangeListener() {
|
||||||
return;
|
@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) {
|
||||||
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user