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

使用SoundPool开发Harmonium App:如何实现按键按住持续发声?

Hey there! I totally get where you're coming from—building a Harmonium app with SoundPool requires a different approach than your piano app, since we need sustained sound on key holds and that "cutoff-when-pressing-another-key" behavior. Let's walk through exactly how to make this work.

Core Concepts to Adjust for Harmonium Behavior

SoundPool is great for short, one-off sounds (like piano keys), but for sustained notes, we need to leverage its looping capability and track active playback streams to manage note cutoffs. Here's the breakdown:

  1. Loop the sound indefinitely when a key is held
  2. Track the active stream ID so we can stop it immediately when another key is pressed or the current key is released
  3. Limit concurrent streams since we only need one note playing at a time

Step-by-Step Implementation

1. Initialize SoundPool with Proper Configuration

First, set up SoundPool to handle looping and single-stream playback (perfect for harmonium's single-note-at-a-time behavior):

private SoundPool soundPool;
private HashMap<Integer, Integer> soundIdMap = new HashMap<>();
private int activeStreamId = -1; // Tracks the currently playing note
private boolean isSoundsLoaded = false; // Ensures we don't play unloaded sounds

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Initialize SoundPool (compatible with old and new Android versions)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        AudioAttributes audioAttrs = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();
        soundPool = new SoundPool.Builder()
                .setMaxStreams(1) // Only allow 1 active stream at a time
                .setAudioAttributes(audioAttrs)
                .build();
    } else {
        soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
    }

    // Load your harmonium sound files (map each key view ID to its sound)
    soundIdMap.put(R.id.key_do, soundPool.load(this, R.raw.harmonium_do, 1));
    soundIdMap.put(R.id.key_re, soundPool.load(this, R.raw.harmonium_re, 1));
    soundIdMap.put(R.id.key_mi, soundPool.load(this, R.raw.harmonium_mi, 1));
    // Add all your keys here

    // Wait for sounds to finish loading before allowing input
    soundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> {
        isSoundsLoaded = true;
    });

    // Attach touch listeners to all your keys
    setupKeyListeners();
}

2. Implement Key Touch Logic for Sustained Playback

Create a touch listener that handles ACTION_DOWN (start looping the note) and ACTION_UP (stop the note), plus cuts off the active note when a new key is pressed:

private void setupKeyListeners() {
    // Example for one key—repeat this for all your harmonium keys
    Button keyDo = findViewById(R.id.key_do);
    keyDo.setOnTouchListener(this::handleKeyTouch);

    Button keyRe = findViewById(R.id.key_re);
    keyRe.setOnTouchListener(this::handleKeyTouch);

    // Add the rest of your keys here
}

private boolean handleKeyTouch(View view, MotionEvent motionEvent) {
    if (!isSoundsLoaded) return false; // Don't do anything until sounds are ready

    int soundId = soundIdMap.get(view.getId());
    switch (motionEvent.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // Stop the currently playing note (if any) before starting a new one
            if (activeStreamId != -1) {
                soundPool.stop(activeStreamId);
            }
            // Play the sound in infinite loop (-1 = loop forever)
            activeStreamId = soundPool.play(
                    soundId,
                    1.0f, // Left volume
                    1.0f, // Right volume
                    1,    // Priority (doesn't matter here since max streams is 1)
                    -1,   // Loop count (-1 = infinite)
                    1.0f  // Playback speed (1.0 = normal)
            );
            return true;
        case MotionEvent.ACTION_UP:
            // Stop the note when the key is released
            if (activeStreamId != -1) {
                soundPool.stop(activeStreamId);
                activeStreamId = -1; // Reset the active stream tracker
            }
            return true;
        default:
            return false;
    }
}

3. Clean Up Resources

Don't forget to release SoundPool when your activity is destroyed to avoid memory leaks:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (soundPool != null) {
        soundPool.release();
        soundPool = null;
    }
}

Important Notes for Smooth Harmonium Playback

  • Use loop-friendly audio files: Make sure your harmonium sound samples have smooth start/end points—this prevents annoying pops or gaps when looping.
  • Stream limit safety: Setting setMaxStreams(1) ensures SoundPool will automatically stop the old stream if you accidentally forget to call stop(), but manual tracking is more reliable for consistent behavior.
  • Load state check: The isSoundsLoaded flag prevents crashes or silent presses if the app tries to play sounds before they finish loading.

内容的提问来源于stack exchange,提问作者just don't be user123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:39:25