Chap 21 Challenge: Playback

This probably isn’t really elegant, but it works. As described in a previous post, use a LinearLayout in fragment_beat_box.xml:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_height="0dp" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:layout_marginLeft="15dp"
        android:id="@+id/playback_label"
        android:text="@string/playback_label" />

    <SeekBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/playback_bar" />
</LinearLayout>

Then set up the new elements in BeatBoxFragment and add a few helper methods:

private FragmentBeatBoxBinding mBinding;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_beat_box, container, false);
    mBinding.recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
    mBinding.recyclerView.setAdapter(new SoundAdapter(mBeatBox.getSounds()));
    mBinding.playbackBar.setMax(150);          //bar goes from 0 to 150, speed 50 to 200
    setPlaybackSpeed(100);
    showSpeed();
    mBinding.playbackBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            Log.d(BeatBox.TAG, "progress value="+seekBar.getProgress());
            showSpeed();
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });
    return mBinding.getRoot();
}
//get speed (50 - 200)
public int getPlaybackSpeed() {
    return mBinding.playbackBar.getProgress()+50;
}

//convert a speed to a bar position
private void setPlaybackSpeed(int speed) {
    if (speed<50) speed = 50;
    if (speed>200) speed = 200;
    mBinding.playbackBar.setProgress(speed-50);
}

private void showSpeed() {
    mBinding.playbackLabel.setText(getResources().getString(R.string.playback_label)+" "+getPlaybackSpeed()+"%");
    mBeatBox.setPlaybackSpeed(getPlaybackSpeed());
}

Finally hook speed up to BeatBox

private int playbackSpeed;

public void setPlaybackSpeed(int speed) {
    playbackSpeed = speed;
}

public void play(Sound sound) {
    Integer soundId = sound.getSoundId();
    if (soundId==null) return;
    mSoundPool.play(soundId, 1.0f, 1.0f, 1, 0, playbackSpeed/100.0f);
}

I’m not really happy about all the funny value conversions in BeatBoxFragment, but wasn’t sure how to refactor. Any suggestions?

1 Like

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Maybe it’s help you

BeatBoxFragment.onCreateView

        binding.seekBarText.setText("Playback Speed: 100%");
        binding.seekBar.setProgress(binding.seekBar.getMax() / 2);
        binding.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float result;
                if (progress < seekBar.getMax() / 2) {
                    result = progress * 0.01f + 0.5f;
                    mBeatBox.setRate(result);
                } else {
                    result = progress * 0.02f;
                    mBeatBox.setRate(result);
                }
                binding.seekBarText.setText("Playback Speed: " + (int)(result * 100) + "%");
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

BeatBox

private float mRate = 1.0f;

public void play(Sound sound) {
        Integer soundId = sound.getSoundId();
        if (soundId == null) {
            return;
        }
        mSoundPool.play(soundId, 1.0f, 1.0f, 1, 0, mRate);
}

    public void setRate(float rate) {
        mRate = rate;
    }

fragment_beat_box

<layout
    xmlns:android="http://schemas.android.com/apk/res/android">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="#FFFFFF">

            <android.support.v7.widget.AppCompatSeekBar
                android:id="@+id/seek_bar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/seek_bar_text"
                />

            <TextView
                android:id="@+id/seek_bar_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingStart="8dp"/>
        </RelativeLayout>

    </FrameLayout>

</layout>

My solution is nearly the same to this one except I created a public global variable in BeatBox to set the play rate and used an if statement in the OnSeekBarChangeListener to avoid 0 division:

//SeekBar
    binding.seekBarPlaySpeed.setProgress(100);
    binding.seekBarPlaySpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            binding.textViewSeekBarProgress.setText(getString(R.string.seek_bar_progress_text,Integer.toString(binding.seekBarPlaySpeed.getProgress())));
            if(progress !=0){mBeatBox.mPlayRate = (float) progress/100;}
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });

how about this

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_beat_box, container, false);

    mBinding.recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
    mBinding.recyclerView.setAdapter(new SoundAdapter(mBeatBox.getSounds()));
    mBinding.seekBarPlaySpeed.setMax(150);
    mBinding.seekBarPlaySpeed.setProgress(75);
    applyPlaybackSpeed();
    mBinding.seekBarPlaySpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int pos, boolean b) {
            applyPlaybackSpeed();
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) { }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) { }
    });

    return mBinding.getRoot();
}

private void applyPlaybackSpeed() {
    float rate = (float) mBinding.seekBarPlaySpeed.getProgress() / mBinding.seekBarPlaySpeed.getMax() + 0.5f;
    mBinding.playSpeedLabel.setText(String.format(getResources().getString(R.string.playback_label), Math.round(rate * 100)));
    mBeatBox.setPlayRate(rate);
}