如何让App中sound2音量随时间按正弦曲线振荡?
Hey Luke, let's tackle your two questions one by one—getting that sine wave volume oscillation working for sound2, and checking over the restored code you're unsure about.
Fixing the Sine Wave Volume Oscillation for sound2
First, let's fix the volume oscillation logic. Your current code has a couple of issues preventing this from working correctly:
- You're using degrees instead of radians: Java's
Math.sin()expects radians, not degrees. Your existing calculationsin((360/totalmili)*(totalTimeEllapsed*1000))will give incorrect values because it's using degree-based math. - Volume is only set once: Right now, you only update the volume when
start == 1, but you need to adjust it every tick of the countdown timer to create the oscillation effect. - Duplicate variable definition: In the
start == 1block, you redefineleftandright, which overrides the earlier calculation (and that second calculation usessin(totalTimeEllapsed)which is way too fast an oscillation).
Here's how to fix this:
- Move the volume calculation to a place where it runs every
onTick(as long as sound2 is playing). - Convert your angle calculation to radians properly.
- Ensure the volume stays within a usable range (0.1 to 1.0, so it never fully mutes, which matches your original intent).
Modified code snippet for the onTick method:
public void onTick(long millisUntilFinished) { secondsEllapsed = (int) ((totalmili + 2000 - millisUntilFinished) / 1000); minutesEllapsed = secondsEllapsed / 60; secondsEllapsed = secondsEllapsed % 60; totalTimeEllapsed = secondsEllapsed + (minutesEllapsed * 60); Log.d("Lucas", "total time elapsed " + totalTimeEllapsed); // Keep your existing elapsed time UI updates here if (totalTimeEllapsed < 10) { errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : 0" + secondsEllapsed); } else if (totalTimeEllapsed >= 10) { errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : " + secondsEllapsed); } seekBarMinutes.setProgress(minutesEllapsed); minutesChanged.setText(Integer.toString(minutesEllapsed)); seekBarSeconds.setProgress(secondsEllapsed); secondsChanged.setText(Integer.toString(secondsEllapsed)); // Calculate sine wave volume - run every tick if sound2 is active if (sound == 2 && sound2.isPlaying()) { // Adjust cycleDuration to control oscillation speed (e.g., totalmili = 1 full cycle over entire duration) double cycleDuration = totalmili; double radians = (2 * Math.PI / cycleDuration) * (totalTimeEllapsed * 1000); double sineValue = Math.sin(radians); // Map sine (-1 to 1) to volume range 0.1 to 1.0 float volume = (float) ((sineValue + 1.0) * 0.9 / 2.0 + 0.1); sound2.setVolume(volume, volume); Log.d("Lucas", "sound2 volume: " + volume); } // Keep your existing sound playback logic for beep and sound2 if(sound == 1){ musicPlaying = beep.isPlaying(); if(musicPlaying == true){ beep.pause(); beep.seekTo(0); beep.start(); } else { beep.start(); } }else if (sound == 2){ if(start ==1) { sound2.seekTo(19); sound2.start(); start = 2; // Remove duplicate volume calculation here - we handle it above }else if(start ==2){ if (totalTimeEllapsed == 11) { sound2.pause(); sound2.seekTo(34); sound2.start(); } else if (totalTimeEllapsed == 22) { sound2.pause(); } } } // Keep your existing percentage and UI color logic here int percentProgress = (int) Math.round(((double) totalTimeEllapsed) / ((double) (totalmili) / 1000) * 100); percentageFinishedAmount.setText(percentProgress + "% "); percentSeekBar.setProgress(percentProgress); errorMessage.setBackgroundColor(Color.argb(255, (int) (percentProgress * 2.5), 0, 0)); errorMessage.setTextColor(Color.argb(255, (int) (255 - (percentProgress * 2.5)), 255, 255)); }
Key changes explained:
- Radian conversion:
2 * Math.PIgives a full 360-degree cycle in radians. Dividing bycycleDuration(total milliseconds for one full sine cycle) sets the oscillation speed. Multiply by elapsed milliseconds to get the current position in the sine wave. - Per-tick volume update: We check if
sound == 2andsound2.isPlaying()every tick, so the volume adjusts continuously. - Removed duplicate variables: The volume calculation is now in one place, avoiding confusing variable shadowing.
Feedback on Restored Code
Looking at the restored minuteEditTextWatcher code, there are a couple of critical fixes and improvements needed:
- Unfinished code: Your method cuts off mid-logic—you need to complete the block (e.g., update
totalmiliwhen minutes change). - Error handling: You don't catch
NumberFormatExceptionif the user enters non-numeric text, which will crash the app. - Enter key cleanup: Add focus clearing after handling the enter key to avoid unintended input.
Fixed minuteEditTextWatcher example:
private final TextWatcher minuteEditTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() == 0) return; // Avoid index out of bounds for empty input // Handle enter key press if (s.charAt(start + count - 1) == '\n') { minuteEditText.getText().replace(start + count - 1, start + count, ""); minuteEditText.clearFocus(); s = minuteEditText.getText(); } try { minutesT = Integer.parseInt(s.toString().trim()); minutesTotal.setText(String.valueOf(minutesT) + " Minutes"); percentageFinishedAmount.setText(" "); // Update total duration when minutes change totalmili = (minutesT * 60000) + (secondsT * 1000); } catch (NumberFormatException e) { errorMessage.setText("Please enter a valid number for minutes"); } } // Implement required empty methods for TextWatcher @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void afterTextChanged(Editable s) {} };
Other quick notes:
- Variable shadowing: In your original code, you define
float lefttwice in the sameonTickmethod—this is bad practice, as it makes code hard to debug. Always avoid redefining variables in nested blocks. - MediaPlayer cleanup: Add
onDestroy()logic to release media players and avoid memory leaks:@Override protected void onDestroy() { super.onDestroy(); if (beep != null) { beep.release(); beep = null; } if (sound2 != null) { sound2.release(); sound2 = null; } }
内容的提问来源于stack exchange,提问作者Luke James
相关产品推荐
相关产品推荐

