【问题标题】:Controlling volume of different sound files independent from each other using sliders使用滑块控制彼此独立的不同声音文件的音量
【发布时间】:2022-01-09 09:52:35
【问题描述】:

我一直在与 Comp sci 类的同行一起研究这个项目,但我不知道如何让 SFX 和音乐拥有自己独立的音量控制。音乐和 SFX 都可以在需要时播放(悬停/单击按钮、菜单音乐等),我为它们制作了滑块(音乐音量和 SFX 音量),但由于某种原因,只有音乐可以被控制。我已经在这里坐了几个小时试图弄清楚为什么它不起作用。 FloatControl 增益确实随滑块更新(我打印了它的值,它工作得很好,只是没有更新音效的实际音量)。我还通过注释掉关于它的滑块控件、音频输入流、增益控制等的所有内容来摆脱与音乐有关的所有内容;就好像 SFX 是程序中唯一与音频相关的东西,但它仍然不起作用。我不明白为什么,因为代码与音乐的代码相同(只是“音乐”现在是“声音”)。

下面的代码并不意味着它本身就可以运行,因为到目前为止实际代码是 605 行,而且这里发布的时间太长了。它确实包含核心组件,所以如果你想设置它来工作,你必须制作 JFrame 和所有按钮,或者让我发布完整的代码和声音文件。

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.sampled.*; 
import java.awt.event.*;
import javax.swing.border.Border; 
import javax.swing.BorderFactory;
import java.io.*;
import java.io.File.*; 
import java.io.IOException;

public class AudioTesting {
  
  // Declare Global Objects 
  
  static final String[] SFXName = {"menuHover", "buttonEnter", "buttonLeave", "gameStart"};
  static final String[] TrackName = {"Bossfight_Incomplete"};
  static final String userName = System.getProperty("user.name");
  
  static Clip sound;
  static Clip music;
  
  static JSlider musicVolumeSlider; 
  static JSlider soundVolumeSlider;
  
  public static void main(String []args){
    
    GameSetting();
  }
  
  public static void GameSetting(){
    
    musicVolumeSlider = new JSlider(-45,6,6);
    soundVolumeSlider = new JSlider(-45,6,6);
    
    musicVolumeSlider.setMajorTickSpacing(5);
    musicVolumeSlider.setMinorTickSpacing(1);
    musicVolumeSlider.setPaintTicks(true);
    //musicVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
   // musicVolumeSlider.setBackground(menuColor);
    musicVolumeSlider.addChangeListener(new SliderListener());
    
    soundVolumeSlider.setMajorTickSpacing(5);
    soundVolumeSlider.setMinorTickSpacing(1);
    soundVolumeSlider.setPaintTicks(true);
 //   soundVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
   // soundVolumeSlider.setBackground(menuColor);
    soundVolumeSlider.addChangeListener(new SliderListener());
    
  }
  
  //manages the loading and playing of sfx 
  public static void SFXManager(int sfx){
    try{
      sound = AudioSystem.getClip();
      File sfxFile = new File("C:\\Users\\" + userName + "\\Documents\\" + SFXName[sfx] + ".wav");
      sound.open(AudioSystem.getAudioInputStream(sfxFile));
      
    }catch (Exception ex){}
    sound.flush();
    sound.start();
  }
  
   // manages the loading and playing of music tracks
  public static void MusicManager(int track){
    try{
    music = AudioSystem.getClip();
    File musicFile = new File("C:\\Users\\" + userName + "\\Documents\\" + TrackName[track] + ".wav");
    music.open(AudioSystem.getAudioInputStream(musicFile));
    
    }catch (Exception ex){}
    music.start();
    music.loop(Clip.LOOP_CONTINUOUSLY); 
  }
  
  static class SliderListener implements ChangeListener {
    
    public void stateChanged(ChangeEvent e) throws IllegalArgumentException {
      float currentMusicVolume = 0;
      float currentSoundVolume = 0;
      
      FloatControl musicGainControl = (FloatControl) music.getControl(FloatControl.Type.MASTER_GAIN);
      FloatControl soundGainControl = (FloatControl) sound.getControl(FloatControl.Type.MASTER_GAIN);
 
     //-------------------------------------------------------------PROBLEM AREA v v v

      //For changing the volume of the music (this works just fine)
      
      if (e.getSource() == musicVolumeSlider){
        currentMusicVolume = musicVolumeSlider.getValue(); 
        
        //if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
        if (currentMusicVolume == -45){
         currentMusicVolume = -80; 
        }
         musicGainControl.setValue(currentMusicVolume); // Reduce volume by slider value
      }
      
     
      //for changing the volume of the sfx
      if (e.getSource() == soundVolumeSlider){
        currentSoundVolume = soundVolumeSlider.getValue(); 
        
        //if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
        if (currentSoundVolume == -45){
         currentSoundVolume = -80; 
        }
        soundGainControl.setValue(currentSoundVolume); // Reduce volume by slider value
      }
    }
    
  }

     //-------------------------------------------------------------PROBLEM AREA ^ ^ ^
  
  // I didn't implement it in here, but here is where all the mouse and event listeners go for the different buttons
  // If a button is hovered over or pressed, it plays a sound from the index that corresponds with that sound
  // I.e. if you hover over a button, call SFXManager(0); which plays the first sound in the array (buttonHover.wav) etc.
  

}   

【问题讨论】:

    标签: java audio slider volume


    【解决方案1】:

    我发现这些浮动控件有点碰运气,部分原因是它们依赖于本地 PC 及其操作系统。如果您想实时更改音量,通常只有主增益有效。主增益更改将影响所有播放声音。

    您可以按照Oracle sound tutorial on audio controls 最后几段的建议编写自己的音量控制。为此需要截取音频输入流,将字节编译为 PCM,将 PCM 乘以音量因子,将 PCM 转换回字节,最后通过SourceDataLine 将字节发送出去。

    这基本上是我写AudioCue时遵循的计划。欢迎您使用该代码库作为滚动您自己的代码库的示例,或者导入并直接使用您项目中的文件。我尝试尽可能地遵循Clip API,同时为每个正在播放的音频实例添加实时音量控制。一个限制是它只适用于wav 文件。但是,如果您可以使用它,请随意使用该库。如果您在设置时遇到任何问题,我很乐意为您解答。

    我目前正在学习如何将该程序作为 Maven 资源提供。我不清楚 Gradle 指令是如何工作的——另一位贡献者做了那部分。将这五个文件复制到您的项目中并使用它们非常容易,只需对导入/打包行稍作修改即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 2012-06-30
      相关资源
      最近更新 更多