Voice Record Button that has ripple effect with users voice. Calculation of decibels from max amplitude by using the following:
power_db = 20 * log10(amp / amp_ref)
Main method consists the following:
if (THRESHOLD >= 0) {
if (rippleRadius - THRESHOLD >= powerDb + MIN_RADIUS || powerDb + MIN_RADIUS >= rippleRadius + THRESHOLD) {
rippleRadius = powerDb + MIN_RADIUS;
backgroundRadius = (int) (rippleRadius * backgroundRippleRatio);
} else {
// if decreasing velocity reached 0, it should simply match with ripple radius
if (((backgroundRadius - rippleRadius) / rippleDecayRate) == 0) {
backgroundRadius = rippleRadius;
} else {
backgroundRadius = backgroundRadius - ((backgroundRadius - rippleRadius) / rippleDecayRate);
}
}
invalidate();
}
The aproximated decibel power of the sound is used to animate the button's ripple effect.
dependencies {
compile "info.kimjihyok:voice-ripple-record-button:${voice-ripple-button-version}"
}
<info.kimjihyok.ripplelibrary.VoiceRippleView
android:id="@+id/voice_ripple_view"
android:layout_width="200dp"
android:layout_height="200dp"
app:rippleColor="@color/colorPrimary"/>
voiceRipple = (VoiceRippleView) findViewById(R.id.voice_ripple_view);
// set view related settings for ripple view
voiceRipple.setRippleColor(ContextCompat.getColor(this, R.color.colorPrimary));
voiceRipple.setRippleSampleRate(Rate.LOW);
voiceRipple.setRippleDecayRate(Rate.HIGH);
voiceRipple.setBackgroundRippleRatio(1.4);
// set recorder related settings for ripple view
voiceRipple.setMediaRecorder(new MediaRecorder());
voiceRipple.setOutputFile(audioFile.getAbsolutePath());
voiceRipple.setAudioSource(MediaRecorder.AudioSource.MIC);
voiceRipple.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
voiceRipple.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// set inner icon for record and recording
voiceRipple.setRecordDrawable(ContextCompat.getDrawable(this, R.drawable.record), ContextCompat.getDrawable(this, R.drawable.recording));
voiceRipple.setIconSize(30);
// change recording status when clicked
voiceRipple.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (voiceRipple.isRecording()) {
voiceRipple.stopRecording();
} else {
try {
voiceRipple.startRecording();
} catch (IOException e) {
Log.e(TAG, "startRecording() error: ", e);
}
}
}
});
// It is required to stop VoiceRippleView at onStop and to destory at onDestory to prevent memory leak and unexpected
@Override
protected void onStop() {
super.onStop();
voiceRipple.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
voiceRipple.onDestroy();
}