You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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:

  1. You're using degrees instead of radians: Java's Math.sin() expects radians, not degrees. Your existing calculation sin((360/totalmili)*(totalTimeEllapsed*1000)) will give incorrect values because it's using degree-based math.
  2. 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.
  3. Duplicate variable definition: In the start == 1 block, you redefine left and right, which overrides the earlier calculation (and that second calculation uses sin(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.PI gives a full 360-degree cycle in radians. Dividing by cycleDuration (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 == 2 and sound2.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:

  1. Unfinished code: Your method cuts off mid-logic—you need to complete the block (e.g., update totalmili when minutes change).
  2. Error handling: You don't catch NumberFormatException if the user enters non-numeric text, which will crash the app.
  3. 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 left twice in the same onTick method—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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:03:31