From ce3d40069d3f20c4449f8786146424dbe083b58a Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Sat, 22 Jul 2023 17:30:24 -0500 Subject: [PATCH 1/7] Add Audio tab to settings in GUI --- .../i18n/megamek/client/messages.properties | 3 + .../client/ui/swing/CommonSettingsDialog.java | 120 +++++++++++++----- .../client/ui/swing/GUIPreferences.java | 9 ++ 3 files changed, 97 insertions(+), 35 deletions(-) diff --git a/megamek/i18n/megamek/client/messages.properties b/megamek/i18n/megamek/client/messages.properties index 43742f33326..88c717b7e61 100644 --- a/megamek/i18n/megamek/client/messages.properties +++ b/megamek/i18n/megamek/client/messages.properties @@ -1209,6 +1209,7 @@ CommonSettingsDialog.locale.Spanish=EspaƱol CommonSettingsDialog.locale=Language/Sprache/\u042f\u0437\u044b\u043a: CommonSettingsDialog.logFileName=Game log filename: CommonSettingsDialog.main=Main +CommonSettingsDialog.audio=Audio CommonSettingsDialog.miniMap=Mini Map CommonSettingsDialog.mmSymbol=Use StratOps unit symbols in the Minimap CommonSettingsDialog.mouseWheelZoom=Mouse wheel zooms map. @@ -1262,6 +1263,8 @@ CommonSettingsDialog.showWrecks=Show wrecks. CommonSettingsDialog.skinFile=Skin File: CommonSettingsDialog.skinFileFail.msg=Error parsing skin specification file, reverting to previous skin! CommonSettingsDialog.skinFileFail.title=Failed to load skin! +CommonSettingsDialog.masterVolume=Master Volume +CommonSettingsDialog.masterVolumeTT=Adjusts the volume of all audio output from the application. CommonSettingsDialog.soundMuteChat=Mute chat notification sound. CommonSettingsDialog.soundMuteMyTurn=Mute my turn notification sound CommonSettingsDialog.soundMuteOthersTurn=Mute others turn notification sound diff --git a/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java b/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java index c8e23de1609..ce6203efdd8 100644 --- a/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java +++ b/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java @@ -137,12 +137,6 @@ private void moveElement(DefaultListModel srcModel, int srcIndex, int trg private final JCheckBox nagForNoUnJamRAC = new JCheckBox(Messages.getString("CommonSettingsDialog.nagForUnJamRAC")); private final JCheckBox animateMove = new JCheckBox(Messages.getString("CommonSettingsDialog.animateMove")); private final JCheckBox showWrecks = new JCheckBox(Messages.getString("CommonSettingsDialog.showWrecks")); - private final JCheckBox soundMuteChat = new JCheckBox(Messages.getString("CommonSettingsDialog.soundMuteChat")); - private JTextField tfSoundMuteChatFileName; - private final JCheckBox soundMuteMyTurn = new JCheckBox(Messages.getString("CommonSettingsDialog.soundMuteMyTurn")); - private JTextField tfSoundMuteMyTurntFileName; - private final JCheckBox soundMuteOthersTurn = new JCheckBox(Messages.getString("CommonSettingsDialog.soundMuteOthersTurn")); - private JTextField tfSoundMuteOthersFileName; private final JCheckBox chkHighQualityGraphics = new JCheckBox(Messages.getString("CommonSettingsDialog.highQualityGraphics")); private final JCheckBox showWpsinTT = new JCheckBox(Messages.getString("CommonSettingsDialog.showWpsinTT")); private final JCheckBox showWpsLocinTT = new JCheckBox(Messages.getString("CommonSettingsDialog.showWpsLocinTT")); @@ -157,6 +151,16 @@ private void moveElement(DefaultListModel srcModel, int srcIndex, int trg private final JCheckBox getFocus = new JCheckBox(Messages.getString("CommonSettingsDialog.getFocus")); private JSlider guiScale; + // Audio Tab + private final JLabel masterVolumeLabel = new JLabel(Messages.getString("CommonSettingsDialog.masterVolume")); + private JSlider masterVolumeSlider; + private final JCheckBox soundMuteChat = new JCheckBox(Messages.getString("CommonSettingsDialog.soundMuteChat")); + private JTextField tfSoundMuteChatFileName; + private final JCheckBox soundMuteMyTurn = new JCheckBox(Messages.getString("CommonSettingsDialog.soundMuteMyTurn")); + private JTextField tfSoundMuteMyTurnFileName; + private final JCheckBox soundMuteOthersTurn = new JCheckBox(Messages.getString("CommonSettingsDialog.soundMuteOthersTurn")); + private JTextField tfSoundMuteOthersFileName; + private final JCheckBox keepGameLog = new JCheckBox(Messages.getString("CommonSettingsDialog.keepGameLog")); private JTextField gameLogFilename; private final JCheckBox stampFilenames = new JCheckBox(Messages.getString("CommonSettingsDialog.stampFilenames")); @@ -411,6 +415,8 @@ public void windowClosing(WindowEvent e) { JScrollPane settingsPane = new JScrollPane(getSettingsPanel()); settingsPane.getVerticalScrollBar().setUnitIncrement(16); + JScrollPane audioPane = new JScrollPane(getAudioPanel()); + audioPane.getVerticalScrollBar().setUnitIncrement(16); JScrollPane keyBindPane = new JScrollPane(getKeyBindPanel()); keyBindPane.getVerticalScrollBar().setUnitIncrement(16); JScrollPane advancedSettingsPane = new JScrollPane(getAdvancedSettingsPanel()); @@ -429,6 +435,7 @@ public void windowClosing(WindowEvent e) { autoDisplayPane.getVerticalScrollBar().setUnitIncrement(16); panTabs.add(Messages.getString("CommonSettingsDialog.main"), settingsPane); + panTabs.add(Messages.getString("CommonSettingsDialog.audio"), audioPane); panTabs.add(Messages.getString("CommonSettingsDialog.keyBinds"), keyBindPane); panTabs.add(Messages.getString("CommonSettingsDialog.gameBoard"), gameBoardPane); panTabs.add(Messages.getString("CommonSettingsDialog.unitDisplay"), unitDisplayPane); @@ -444,6 +451,67 @@ public void windowClosing(WindowEvent e) { return panTabs; } + private JPanel getAudioPanel() { + List> comps = new ArrayList<>(); + ArrayList row; + + row = new ArrayList<>(); + row.add(masterVolumeLabel); + comps.add(row); + + masterVolumeSlider = new JSlider(); + masterVolumeSlider.setMinorTickSpacing(5); + masterVolumeSlider.setMajorTickSpacing(25); + masterVolumeSlider.setMinimum(0); + masterVolumeSlider.setMaximum(100); + Hashtable table = new Hashtable<>(); + table.put(0, new JLabel("0%")); + table.put(25, new JLabel("25%")); + table.put(50, new JLabel("50%")); + table.put(75, new JLabel("75%")); + table.put(100, new JLabel("100%")); + masterVolumeSlider.setLabelTable(table); + masterVolumeSlider.setPaintTicks(true); + masterVolumeSlider.setPaintLabels(true); + masterVolumeSlider.setMaximumSize(new Dimension(250, 100)); + masterVolumeSlider.setToolTipText(Messages.getString("CommonSettingsDialog.masterVolumeTT")); + row = new ArrayList<>(); + row.add(masterVolumeSlider); + comps.add(row); + + addLineSpacer(comps); + + comps.add(checkboxEntry(soundMuteChat, null)); + + tfSoundMuteChatFileName = new JTextField(5); + tfSoundMuteChatFileName.setMaximumSize(new Dimension(450, 40)); + row = new ArrayList<>(); + row.add(tfSoundMuteChatFileName); + comps.add(row); + + addLineSpacer(comps); + + comps.add(checkboxEntry(soundMuteMyTurn, null)); + + tfSoundMuteMyTurnFileName = new JTextField(5); + tfSoundMuteMyTurnFileName.setMaximumSize(new Dimension(450, 40)); + row = new ArrayList<>(); + row.add(tfSoundMuteMyTurnFileName); + comps.add(row); + + addLineSpacer(comps); + + comps.add(checkboxEntry(soundMuteOthersTurn, null)); + + tfSoundMuteOthersFileName = new JTextField(5); + tfSoundMuteOthersFileName.setMaximumSize(new Dimension(450, 40)); + row = new ArrayList<>(); + row.add(tfSoundMuteOthersFileName); + comps.add(row); + + return createSettingsPanel(comps); + } + private JPanel getGameBoardPanel() { List> comps = new ArrayList<>(); ArrayList row; @@ -1377,27 +1445,6 @@ private JPanel getSettingsPanel() { addLineSpacer(comps); - comps.add(checkboxEntry(soundMuteChat, null)); - tfSoundMuteChatFileName = new JTextField(5); - tfSoundMuteChatFileName.setMaximumSize(new Dimension(450, 40)); - row = new ArrayList<>(); - row.add(tfSoundMuteChatFileName); - comps.add(row); - comps.add(checkboxEntry(soundMuteMyTurn, null)); - tfSoundMuteMyTurntFileName = new JTextField(5); - tfSoundMuteMyTurntFileName.setMaximumSize(new Dimension(450, 40)); - row = new ArrayList<>(); - row.add(tfSoundMuteMyTurntFileName); - comps.add(row); - comps.add(checkboxEntry(soundMuteOthersTurn, null)); - tfSoundMuteOthersFileName = new JTextField(5); - tfSoundMuteOthersFileName.setMaximumSize(new Dimension(450, 40)); - row = new ArrayList<>(); - row.add(tfSoundMuteOthersFileName); - comps.add(row); - - addLineSpacer(comps); - JLabel unitStartCharLabel = new JLabel(Messages.getString("CommonSettingsDialog.protoMechUnitCodes")); unitStartChar = new JComboBox<>(); // Add option for "A, B, C, D..." @@ -1492,9 +1539,6 @@ public void setVisible(boolean visible) { nagForNoUnJamRAC.setSelected(GUIP.getNagForNoUnJamRAC()); animateMove.setSelected(GUIP.getShowMoveStep()); showWrecks.setSelected(GUIP.getShowWrecks()); - soundMuteChat.setSelected(GUIP.getSoundMuteChat()); - soundMuteMyTurn.setSelected(GUIP.getSoundMuteMyTurn()); - soundMuteOthersTurn.setSelected(GUIP.getSoundMuteOthersTurn()); tooltipDelay.setText(Integer.toString(GUIP.getTooltipDelay())); tooltipDismissDelay.setText(Integer.toString(GUIP.getTooltipDismissDelay())); tooltipDistSupression.setText(Integer.toString(GUIP.getTooltipDistSuppression())); @@ -1517,8 +1561,12 @@ public void setVisible(boolean visible) { } } + masterVolumeSlider.setValue(GUIP.getMasterVolume()); + soundMuteChat.setSelected(GUIP.getSoundMuteChat()); + soundMuteMyTurn.setSelected(GUIP.getSoundMuteMyTurn()); + soundMuteOthersTurn.setSelected(GUIP.getSoundMuteOthersTurn()); tfSoundMuteChatFileName.setText(GUIP.getSoundBingFilenameChat()); - tfSoundMuteMyTurntFileName.setText(GUIP.getSoundBingFilenameMyTurn()); + tfSoundMuteMyTurnFileName.setText(GUIP.getSoundBingFilenameMyTurn()); tfSoundMuteOthersFileName.setText(GUIP.getSoundBingFilenameOthersTurn()); maxPathfinderTime.setText(Integer.toString(CP.getMaxPathfinderTime())); @@ -1834,9 +1882,6 @@ protected void okAction() { GUIP.setNagForNoUnJamRAC(nagForNoUnJamRAC.isSelected()); GUIP.setShowMoveStep(animateMove.isSelected()); GUIP.setShowWrecks(showWrecks.isSelected()); - GUIP.setSoundMuteChat(soundMuteChat.isSelected()); - GUIP.setSoundMuteMyTurn(soundMuteMyTurn.isSelected()); - GUIP.setSoundMuteOthersTurn(soundMuteOthersTurn.isSelected()); GUIP.setShowWpsinTT(showWpsinTT.isSelected()); GUIP.setShowWpsLocinTT(showWpsLocinTT.isSelected()); GUIP.setshowArmorMiniVisTT(showArmorMiniVisTT.isSelected()); @@ -1928,8 +1973,13 @@ protected void okAction() { GUIP.setMoveDefaultClimbMode(moveDefaultClimbMode.isSelected()); + GUIP.setMasterVolume(masterVolumeSlider.getValue()); + GUIP.setSoundMuteChat(soundMuteChat.isSelected()); + GUIP.setSoundMuteMyTurn(soundMuteMyTurn.isSelected()); + GUIP.setSoundMuteOthersTurn(soundMuteOthersTurn.isSelected()); + GUIP.setSoundBingFilenameChat(tfSoundMuteChatFileName.getText()); - GUIP.setSoundBingFilenameMyTurn(tfSoundMuteMyTurntFileName.getText()); + GUIP.setSoundBingFilenameMyTurn(tfSoundMuteMyTurnFileName.getText()); GUIP.setSoundBingFilenameOthersTurn(tfSoundMuteOthersFileName.getText()); try { diff --git a/megamek/src/megamek/client/ui/swing/GUIPreferences.java b/megamek/src/megamek/client/ui/swing/GUIPreferences.java index 20750abea72..15452ff6d89 100644 --- a/megamek/src/megamek/client/ui/swing/GUIPreferences.java +++ b/megamek/src/megamek/client/ui/swing/GUIPreferences.java @@ -284,6 +284,7 @@ public class GUIPreferences extends PreferenceStoreProxy { public static final String SOUND_BING_FILENAME_CHAT = "SoundBingFilenameChat"; public static final String SOUND_BING_FILENAME_MY_TURN = "SoundBingFilenameMyTurn"; public static final String SOUND_BING_FILENAME_OTHERS_TURN = "SoundBingFilenameOthersTurn"; + public static final String MASTER_VOLUME = "MasterVolume"; public static final String SOUND_MUTE_CHAT = "SoundMuteChat"; public static final String SOUND_MUTE_MY_TURN = "SoundMuteMyTurn"; public static final String SOUND_MUTE_OTHERS_TURN = "SoundMuteOthersTurn"; @@ -1343,6 +1344,10 @@ public boolean getShowWrecks() { return store.getBoolean(SHOW_WRECKS); } + public int getMasterVolume() { + return store.getInt(MASTER_VOLUME); + } + public String getSoundBingFilenameChat() { return store.getString(SOUND_BING_FILENAME_CHAT); } @@ -2112,6 +2117,10 @@ public void setSoundBingFilenameOthersTurn(String name) { store.setValue(SOUND_BING_FILENAME_OTHERS_TURN, name); } + public void setMasterVolume(int state) { + store.setValue(MASTER_VOLUME, state); + } + public void setSoundMuteChat(boolean state) { store.setValue(SOUND_MUTE_CHAT, state); } From 76ee81161119afa6978b58ad66a46a0fb574c499 Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Sat, 22 Jul 2023 21:28:18 -0500 Subject: [PATCH 2/7] Create SoundManager and Sound classes Wire up new classes to use the master volume setting to change the volume of sound output --- .../megamek/client/ui/swing/ClientGUI.java | 46 ++-------- .../client/ui/swing/GUIPreferences.java | 2 + .../megamek/client/ui/swing/audio/Sound.java | 25 +++++ .../client/ui/swing/audio/SoundManager.java | 92 +++++++++++++++++++ 4 files changed, 126 insertions(+), 39 deletions(-) create mode 100644 megamek/src/megamek/client/ui/swing/audio/Sound.java create mode 100644 megamek/src/megamek/client/ui/swing/audio/SoundManager.java diff --git a/megamek/src/megamek/client/ui/swing/ClientGUI.java b/megamek/src/megamek/client/ui/swing/ClientGUI.java index f49135e8b26..3d4b20de135 100644 --- a/megamek/src/megamek/client/ui/swing/ClientGUI.java +++ b/megamek/src/megamek/client/ui/swing/ClientGUI.java @@ -29,6 +29,7 @@ import megamek.client.ui.dialogs.helpDialogs.AbstractHelpDialog; import megamek.client.ui.dialogs.helpDialogs.MMReadMeHelpDialog; import megamek.client.ui.enums.DialogResult; +import megamek.client.ui.swing.audio.SoundManager; import megamek.client.ui.swing.boardview.BoardView; import megamek.client.ui.swing.dialog.AbstractUnitSelectorDialog; import megamek.client.ui.swing.dialog.MegaMekUnitSelectorDialog; @@ -80,6 +81,7 @@ public class ClientGUI extends JPanel implements BoardViewListener, private static final long serialVersionUID = 3913466735610109147L; private static final GUIPreferences GUIP = GUIPreferences.getInstance(); + private SoundManager SM = SoundManager.getInstance(); private static final ClientPreferences CP = PreferenceManager.getClientPreferences(); private static final String FILENAME_ICON_16X16 = "megamek-icon-16x16.png"; @@ -263,13 +265,6 @@ public class ClientGUI extends JPanel implements BoardViewListener, private File curfileBoardImage; private File curfileBoard; - /** - * Cache for the "bing" soundclip. - */ - private Clip bingClipChat; - private Clip bingClipMyTurn; - private Clip bingClipOthersTurn; - /** * Map each phase to the name of the card for the main display area. */ @@ -341,31 +336,13 @@ public ClientGUI(Client client, MegaMekController c) { this.addComponentListener(this); this.client = client; controller = c; - loadSoundFiles(); panMain.setLayout(cardsMain); panSecondary.setLayout(cardsSecondary); JPanel panDisplay = new JPanel(new BorderLayout()); panDisplay.add(panMain, BorderLayout.CENTER); panDisplay.add(panSecondary, BorderLayout.SOUTH); add(panDisplay, BorderLayout.CENTER); - } - - private void loadSoundFiles() { - if (bingClipChat != null) { - bingClipChat.close(); - } - - if (bingClipMyTurn != null) { - bingClipMyTurn.close(); - } - - if (bingClipOthersTurn != null) { - bingClipOthersTurn.close(); - } - - bingClipChat = loadSoundClip(GUIP.getSoundBingFilenameChat()); - bingClipMyTurn = loadSoundClip(GUIP.getSoundBingFilenameMyTurn()); - bingClipOthersTurn = loadSoundClip(GUIP.getSoundBingFilenameOthersTurn()); + SM.loadSoundFiles(); } public BoardView getBoardView() { @@ -2154,24 +2131,15 @@ public void loadPreviewImage(JLabel bp, Entity entity, Player player) { * Make a "bing" sound. */ public void bingChat() { - if (!GUIP.getSoundMuteChat() && (bingClipMyTurn != null)) { - bingClipChat.setFramePosition(0); - bingClipChat.start(); - } + SM.bingChat(); } public void bingMyTurn() { - if (!GUIP.getSoundMuteMyTurn() && (bingClipMyTurn != null)) { - bingClipMyTurn.setFramePosition(0); - bingClipMyTurn.start(); - } + SM.bingMyTurn(); } public void bingOthersTurn() { - if (!GUIP.getSoundMuteOthersTurn() && (bingClipMyTurn != null)) { - bingClipOthersTurn.setFramePosition(0); - bingClipOthersTurn.start(); - } + SM.bingOthersTurn(); } private void setWeaponOrderPrefs(boolean prefChange) { @@ -2899,7 +2867,7 @@ public void preferenceChange(PreferenceChangeEvent e) { } else if ((e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_CHAT)) || (e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_MY_TURN)) || (e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_OTHERS_TURN))) { - loadSoundFiles(); + SM.loadSoundFiles(); } } } diff --git a/megamek/src/megamek/client/ui/swing/GUIPreferences.java b/megamek/src/megamek/client/ui/swing/GUIPreferences.java index 15452ff6d89..ce046ae92c9 100644 --- a/megamek/src/megamek/client/ui/swing/GUIPreferences.java +++ b/megamek/src/megamek/client/ui/swing/GUIPreferences.java @@ -654,6 +654,8 @@ protected GUIPreferences() { store.setDefault(SHOW_MAPHEX_POPUP, true); store.setDefault(SHOW_MOVE_STEP, true); store.setDefault(SHOW_WRECKS, true); + + store.setDefault(MASTER_VOLUME, 100); store.setDefault(SOUND_BING_FILENAME_CHAT, "data/sounds/call.wav"); store.setDefault(SOUND_BING_FILENAME_MY_TURN, "data/sounds/call.wav"); store.setDefault(SOUND_BING_FILENAME_OTHERS_TURN, "data/sounds/call.wav"); diff --git a/megamek/src/megamek/client/ui/swing/audio/Sound.java b/megamek/src/megamek/client/ui/swing/audio/Sound.java new file mode 100644 index 00000000000..f9c010057d2 --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/audio/Sound.java @@ -0,0 +1,25 @@ +package megamek.client.ui.swing.audio; + +import javax.sound.sampled.Clip; +import javax.sound.sampled.FloatControl; + +public class Sound +{ + private final Clip clip; + + public Sound(final Clip clip) { + this.clip = clip; + } + + public void play() { + if (clip != null) { + clip.setFramePosition(0); + clip.start(); + } + } + + public void setVolume(float volume) { + FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + gainControl.setValue(20f * (float) Math.log10(volume)); + } +} diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java new file mode 100644 index 00000000000..c1bea0ba9a4 --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java @@ -0,0 +1,92 @@ +package megamek.client.ui.swing.audio; + +import megamek.client.ui.Messages; +import megamek.client.ui.swing.GUIPreferences; +import megamek.common.annotations.Nullable; +import org.apache.logging.log4j.LogManager; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import java.io.File; + +public class SoundManager { + private static final SoundManager instance = new SoundManager(); + + private static final GUIPreferences GUIP = GUIPreferences.getInstance(); + + private Sound bingChat; + private Sound bingMyTurn; + private Sound bingOthersTurn; + + public static SoundManager getInstance() { + return instance; + } + + protected SoundManager() { + } + + public void bingChat() { + if(!GUIP.getSoundMuteChat()) { + setVolume(bingChat); + bingChat.play(); + } + } + + public void bingMyTurn() { + if(!GUIP.getSoundMuteMyTurn()) { + setVolume(bingMyTurn); + bingMyTurn.play(); + } + } + + public void bingOthersTurn() { + if(!GUIP.getSoundMuteOthersTurn()) { + setVolume(bingOthersTurn); + bingOthersTurn.play(); + } + } + + public void loadSoundFiles() { + final Clip bingClipChat = loadSoundClip(GUIP.getSoundBingFilenameChat()); + bingChat = new Sound(bingClipChat); + + final Clip bingClipMyTurn = loadSoundClip(GUIP.getSoundBingFilenameMyTurn()); + bingMyTurn = new Sound(bingClipMyTurn); + + final Clip bingClipOthersTurn = loadSoundClip(GUIP.getSoundBingFilenameOthersTurn()); + bingOthersTurn = new Sound(bingClipOthersTurn); + } + + private @Nullable Clip loadSoundClip(@Nullable String filename) { + if (filename == null) { + return null; + } + + final File file = new File(filename); + + if (!file.exists()) { + LogManager.getLogger().error(Messages.getString("SoundManager.failedToLoadAudioFile") + " " + filename); + return null; + } + + try { + Clip clip = AudioSystem.getClip(); + try (AudioInputStream ais = AudioSystem.getAudioInputStream(file)) { + clip.open(ais); + return clip; + } + } catch (Exception ex) { + LogManager.getLogger().error("SoundManager was unable to load the sound", ex); + return null; + } + } + + private void setVolume(final Sound sound) { + float volume = GUIP.getMasterVolume() / 100.0f; + + if(sound != null) { + sound.setVolume(volume); + } + } +} From eec25ae4235219cbe18e9738969d25a9a1e9632b Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Sat, 22 Jul 2023 22:32:14 -0500 Subject: [PATCH 3/7] Add copyright text and comments to SoundManager --- .../megamek/client/ui/swing/audio/Sound.java | 19 ++++++++++++ .../client/ui/swing/audio/SoundManager.java | 31 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/megamek/src/megamek/client/ui/swing/audio/Sound.java b/megamek/src/megamek/client/ui/swing/audio/Sound.java index f9c010057d2..fa750721396 100644 --- a/megamek/src/megamek/client/ui/swing/audio/Sound.java +++ b/megamek/src/megamek/client/ui/swing/audio/Sound.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2023 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ + package megamek.client.ui.swing.audio; import javax.sound.sampled.Clip; diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java index c1bea0ba9a4..285c221b7d8 100644 --- a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java +++ b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2023 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ + package megamek.client.ui.swing.audio; import megamek.client.ui.Messages; @@ -26,6 +45,9 @@ public static SoundManager getInstance() { protected SoundManager() { } + /** + * Plays a sound when a chat message is entered + */ public void bingChat() { if(!GUIP.getSoundMuteChat()) { setVolume(bingChat); @@ -33,6 +55,9 @@ public void bingChat() { } } + /** + * Plays a sound when it is the user's turn during a game + */ public void bingMyTurn() { if(!GUIP.getSoundMuteMyTurn()) { setVolume(bingMyTurn); @@ -40,6 +65,9 @@ public void bingMyTurn() { } } + /** + * Plays a sound when it is another user's turn during a game + */ public void bingOthersTurn() { if(!GUIP.getSoundMuteOthersTurn()) { setVolume(bingOthersTurn); @@ -47,6 +75,9 @@ public void bingOthersTurn() { } } + /** + * Loads the sound files from the paths given in the client settings + */ public void loadSoundFiles() { final Clip bingClipChat = loadSoundClip(GUIP.getSoundBingFilenameChat()); bingChat = new Sound(bingClipChat); From 7973de934859e2fc6f363b6a9869f5e63e7227e8 Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Sun, 23 Jul 2023 17:24:35 -0500 Subject: [PATCH 4/7] Change SoundManager from Singleton Add AudioService interface for other possible users, and SoundType enum for current sounds --- .../megamek/client/ui/swing/ClientGUI.java | 19 ++-- .../client/ui/swing/audio/AudioService.java | 25 +++++ .../megamek/client/ui/swing/audio/Sound.java | 4 + .../client/ui/swing/audio/SoundManager.java | 92 +++++++++---------- .../client/ui/swing/audio/SoundType.java | 26 ++++++ 5 files changed, 114 insertions(+), 52 deletions(-) create mode 100644 megamek/src/megamek/client/ui/swing/audio/AudioService.java create mode 100644 megamek/src/megamek/client/ui/swing/audio/SoundType.java diff --git a/megamek/src/megamek/client/ui/swing/ClientGUI.java b/megamek/src/megamek/client/ui/swing/ClientGUI.java index 3d4b20de135..8174cd061e0 100644 --- a/megamek/src/megamek/client/ui/swing/ClientGUI.java +++ b/megamek/src/megamek/client/ui/swing/ClientGUI.java @@ -29,7 +29,9 @@ import megamek.client.ui.dialogs.helpDialogs.AbstractHelpDialog; import megamek.client.ui.dialogs.helpDialogs.MMReadMeHelpDialog; import megamek.client.ui.enums.DialogResult; +import megamek.client.ui.swing.audio.AudioService; import megamek.client.ui.swing.audio.SoundManager; +import megamek.client.ui.swing.audio.SoundType; import megamek.client.ui.swing.boardview.BoardView; import megamek.client.ui.swing.dialog.AbstractUnitSelectorDialog; import megamek.client.ui.swing.dialog.MegaMekUnitSelectorDialog; @@ -81,7 +83,6 @@ public class ClientGUI extends JPanel implements BoardViewListener, private static final long serialVersionUID = 3913466735610109147L; private static final GUIPreferences GUIP = GUIPreferences.getInstance(); - private SoundManager SM = SoundManager.getInstance(); private static final ClientPreferences CP = PreferenceManager.getClientPreferences(); private static final String FILENAME_ICON_16X16 = "megamek-icon-16x16.png"; @@ -323,6 +324,12 @@ public class ClientGUI extends JPanel implements BoardViewListener, * shot. */ private int pointblankEID = Entity.NONE; + + /** + * Audio system + */ + private final AudioService audioService = new SoundManager(); + //endregion Variable Declarations /** @@ -342,7 +349,7 @@ public ClientGUI(Client client, MegaMekController c) { panDisplay.add(panMain, BorderLayout.CENTER); panDisplay.add(panSecondary, BorderLayout.SOUTH); add(panDisplay, BorderLayout.CENTER); - SM.loadSoundFiles(); + audioService.loadSoundFiles(); } public BoardView getBoardView() { @@ -2131,15 +2138,15 @@ public void loadPreviewImage(JLabel bp, Entity entity, Player player) { * Make a "bing" sound. */ public void bingChat() { - SM.bingChat(); + audioService.playSound(SoundType.BING_CHAT); } public void bingMyTurn() { - SM.bingMyTurn(); + audioService.playSound(SoundType.BING_MY_TURN); } public void bingOthersTurn() { - SM.bingOthersTurn(); + audioService.playSound(SoundType.BING_OTHERS_TURN); } private void setWeaponOrderPrefs(boolean prefChange) { @@ -2867,7 +2874,7 @@ public void preferenceChange(PreferenceChangeEvent e) { } else if ((e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_CHAT)) || (e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_MY_TURN)) || (e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_OTHERS_TURN))) { - SM.loadSoundFiles(); + audioService.loadSoundFiles(); } } } diff --git a/megamek/src/megamek/client/ui/swing/audio/AudioService.java b/megamek/src/megamek/client/ui/swing/audio/AudioService.java new file mode 100644 index 00000000000..f53fb104bc2 --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/audio/AudioService.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ + +package megamek.client.ui.swing.audio; + +public interface AudioService { + void loadSoundFiles(); + void playSound(SoundType id); +} diff --git a/megamek/src/megamek/client/ui/swing/audio/Sound.java b/megamek/src/megamek/client/ui/swing/audio/Sound.java index fa750721396..9fb3cad3a61 100644 --- a/megamek/src/megamek/client/ui/swing/audio/Sound.java +++ b/megamek/src/megamek/client/ui/swing/audio/Sound.java @@ -38,6 +38,10 @@ public void play() { } public void setVolume(float volume) { + if(volume < 0.0f || volume > 1.0f) { + throw new IllegalArgumentException("Invalid volume: " + volume); + } + FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); gainControl.setValue(20f * (float) Math.log10(volume)); } diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java index 285c221b7d8..6587ab40a2f 100644 --- a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java +++ b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java @@ -28,65 +28,65 @@ import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import java.io.File; +import java.util.HashMap; +import java.util.Map; -public class SoundManager { - private static final SoundManager instance = new SoundManager(); - +public class SoundManager implements AudioService { private static final GUIPreferences GUIP = GUIPreferences.getInstance(); - private Sound bingChat; - private Sound bingMyTurn; - private Sound bingOthersTurn; - - public static SoundManager getInstance() { - return instance; - } - - protected SoundManager() { - } + private final Map sounds = new HashMap<>(); /** - * Plays a sound when a chat message is entered + * Loads the sound files from the paths given in the client settings */ - public void bingChat() { - if(!GUIP.getSoundMuteChat()) { - setVolume(bingChat); - bingChat.play(); + @Override + public void loadSoundFiles() { + if(!sounds.isEmpty()) { + sounds.clear(); } - } - /** - * Plays a sound when it is the user's turn during a game - */ - public void bingMyTurn() { - if(!GUIP.getSoundMuteMyTurn()) { - setVolume(bingMyTurn); - bingMyTurn.play(); - } - } + Sound sound; - /** - * Plays a sound when it is another user's turn during a game - */ - public void bingOthersTurn() { - if(!GUIP.getSoundMuteOthersTurn()) { - setVolume(bingOthersTurn); - bingOthersTurn.play(); - } - } - - /** - * Loads the sound files from the paths given in the client settings - */ - public void loadSoundFiles() { final Clip bingClipChat = loadSoundClip(GUIP.getSoundBingFilenameChat()); - bingChat = new Sound(bingClipChat); + sound = new Sound(bingClipChat); + sounds.put(0, sound); final Clip bingClipMyTurn = loadSoundClip(GUIP.getSoundBingFilenameMyTurn()); - bingMyTurn = new Sound(bingClipMyTurn); + sound = new Sound(bingClipMyTurn); + sounds.put(1, sound); final Clip bingClipOthersTurn = loadSoundClip(GUIP.getSoundBingFilenameOthersTurn()); - bingOthersTurn = new Sound(bingClipOthersTurn); + sound = new Sound(bingClipOthersTurn); + sounds.put(2, sound); + } + + @Override + public void playSound(SoundType id) { + Sound sound = null; + + switch(id) + { + case BING_CHAT: + if(!GUIP.getSoundMuteChat()) { + sound = sounds.get(0); + } + break; + case BING_MY_TURN: + if(!GUIP.getSoundMuteMyTurn()) { + sound = sounds.get(1); + } + break; + case BING_OTHERS_TURN: + if(!GUIP.getSoundMuteMyTurn()) { + sound = sounds.get(2); + } + break; + } + + if(sound != null) { + setVolume(sound); + sound.play(); + } } private @Nullable Clip loadSoundClip(@Nullable String filename) { @@ -114,7 +114,7 @@ public void loadSoundFiles() { } private void setVolume(final Sound sound) { - float volume = GUIP.getMasterVolume() / 100.0f; + final float volume = GUIP.getMasterVolume() / 100.0f; if(sound != null) { sound.setVolume(volume); diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundType.java b/megamek/src/megamek/client/ui/swing/audio/SoundType.java new file mode 100644 index 00000000000..4dd32b2a44b --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/audio/SoundType.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ + +package megamek.client.ui.swing.audio; + +public enum SoundType { + BING_CHAT, + BING_MY_TURN, + BING_OTHERS_TURN, +} From a6ceeb804e4079fdd5527b27ff6e4276bcfa15b9 Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Wed, 2 Aug 2023 12:11:15 -0500 Subject: [PATCH 5/7] Update SoundManager to expose setVolume and change volume when setting is changed --- .../megamek/client/ui/swing/ClientGUI.java | 3 +++ .../client/ui/swing/audio/AudioService.java | 1 + .../megamek/client/ui/swing/audio/Sound.java | 10 +++++--- .../client/ui/swing/audio/SoundManager.java | 25 +++++++++++-------- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/megamek/src/megamek/client/ui/swing/ClientGUI.java b/megamek/src/megamek/client/ui/swing/ClientGUI.java index 8174cd061e0..988c9ef8873 100644 --- a/megamek/src/megamek/client/ui/swing/ClientGUI.java +++ b/megamek/src/megamek/client/ui/swing/ClientGUI.java @@ -349,6 +349,7 @@ public ClientGUI(Client client, MegaMekController c) { panDisplay.add(panMain, BorderLayout.CENTER); panDisplay.add(panSecondary, BorderLayout.SOUTH); add(panDisplay, BorderLayout.CENTER); + audioService.loadSoundFiles(); } @@ -2875,6 +2876,8 @@ public void preferenceChange(PreferenceChangeEvent e) { || (e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_MY_TURN)) || (e.getName().equals(GUIPreferences.SOUND_BING_FILENAME_OTHERS_TURN))) { audioService.loadSoundFiles(); + } else if (e.getName().equals(GUIPreferences.MASTER_VOLUME)) { + audioService.setVolume(); } } } diff --git a/megamek/src/megamek/client/ui/swing/audio/AudioService.java b/megamek/src/megamek/client/ui/swing/audio/AudioService.java index f53fb104bc2..d5de80519d3 100644 --- a/megamek/src/megamek/client/ui/swing/audio/AudioService.java +++ b/megamek/src/megamek/client/ui/swing/audio/AudioService.java @@ -22,4 +22,5 @@ public interface AudioService { void loadSoundFiles(); void playSound(SoundType id); + void setVolume(); } diff --git a/megamek/src/megamek/client/ui/swing/audio/Sound.java b/megamek/src/megamek/client/ui/swing/audio/Sound.java index 9fb3cad3a61..b9db9601e65 100644 --- a/megamek/src/megamek/client/ui/swing/audio/Sound.java +++ b/megamek/src/megamek/client/ui/swing/audio/Sound.java @@ -19,6 +19,8 @@ package megamek.client.ui.swing.audio; +import megamek.common.annotations.Nullable; + import javax.sound.sampled.Clip; import javax.sound.sampled.FloatControl; @@ -26,7 +28,7 @@ public class Sound { private final Clip clip; - public Sound(final Clip clip) { + public Sound(@Nullable final Clip clip) { this.clip = clip; } @@ -42,7 +44,9 @@ public void setVolume(float volume) { throw new IllegalArgumentException("Invalid volume: " + volume); } - FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); - gainControl.setValue(20f * (float) Math.log10(volume)); + if(clip != null) { + FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + gainControl.setValue(20f * (float) Math.log10(volume)); + } } } diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java index 6587ab40a2f..efbc7d2e200 100644 --- a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java +++ b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java @@ -28,13 +28,13 @@ import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import java.io.File; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; public class SoundManager implements AudioService { private static final GUIPreferences GUIP = GUIPreferences.getInstance(); - private final Map sounds = new HashMap<>(); + private final List sounds = new ArrayList<>(); /** * Loads the sound files from the paths given in the client settings @@ -49,15 +49,17 @@ public void loadSoundFiles() { final Clip bingClipChat = loadSoundClip(GUIP.getSoundBingFilenameChat()); sound = new Sound(bingClipChat); - sounds.put(0, sound); + sounds.add(sound); final Clip bingClipMyTurn = loadSoundClip(GUIP.getSoundBingFilenameMyTurn()); sound = new Sound(bingClipMyTurn); - sounds.put(1, sound); + sounds.add(sound); final Clip bingClipOthersTurn = loadSoundClip(GUIP.getSoundBingFilenameOthersTurn()); sound = new Sound(bingClipOthersTurn); - sounds.put(2, sound); + sounds.add(sound); + + setVolume(); } @Override @@ -84,11 +86,16 @@ public void playSound(SoundType id) { } if(sound != null) { - setVolume(sound); sound.play(); } } + public void setVolume() { + for (var sound: sounds) { + setVolume(sound); + } + } + private @Nullable Clip loadSoundClip(@Nullable String filename) { if (filename == null) { return null; @@ -116,8 +123,6 @@ public void playSound(SoundType id) { private void setVolume(final Sound sound) { final float volume = GUIP.getMasterVolume() / 100.0f; - if(sound != null) { - sound.setVolume(volume); - } + sound.setVolume(volume); } } From 2bb9fe808c807854dadccbbe164a0a1dc14b7b77 Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Sun, 6 Aug 2023 19:42:19 -0500 Subject: [PATCH 6/7] Update SoundManager.java --- megamek/src/megamek/client/ui/swing/audio/SoundManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java index efbc7d2e200..3c8ded80c6a 100644 --- a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java +++ b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java @@ -90,6 +90,7 @@ public void playSound(SoundType id) { } } + @Override public void setVolume() { for (var sound: sounds) { setVolume(sound); From a9fd87fb231bcc17316db34e7525ce6392b0c1cc Mon Sep 17 00:00:00 2001 From: Sensualcoder Date: Mon, 7 Aug 2023 17:50:48 -0500 Subject: [PATCH 7/7] Add javadoc comments to methods --- megamek/src/megamek/client/ui/swing/audio/Sound.java | 10 ++++++++++ .../megamek/client/ui/swing/audio/SoundManager.java | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/megamek/src/megamek/client/ui/swing/audio/Sound.java b/megamek/src/megamek/client/ui/swing/audio/Sound.java index b9db9601e65..b1e15e1a571 100644 --- a/megamek/src/megamek/client/ui/swing/audio/Sound.java +++ b/megamek/src/megamek/client/ui/swing/audio/Sound.java @@ -24,6 +24,9 @@ import javax.sound.sampled.Clip; import javax.sound.sampled.FloatControl; +/** + * Contains a sound Clip to allow for managing playback + */ public class Sound { private final Clip clip; @@ -32,6 +35,9 @@ public Sound(@Nullable final Clip clip) { this.clip = clip; } + /** + * Starts playback of the contained sound file, if one has been loaded + */ public void play() { if (clip != null) { clip.setFramePosition(0); @@ -39,6 +45,10 @@ public void play() { } } + /** + * Sets the output volume of the sound + * @param volume - float value of the output volume + */ public void setVolume(float volume) { if(volume < 0.0f || volume > 1.0f) { throw new IllegalArgumentException("Invalid volume: " + volume); diff --git a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java index 3c8ded80c6a..d6ca22b8b24 100644 --- a/megamek/src/megamek/client/ui/swing/audio/SoundManager.java +++ b/megamek/src/megamek/client/ui/swing/audio/SoundManager.java @@ -62,6 +62,10 @@ public void loadSoundFiles() { setVolume(); } + /** + * Starts playback of a sound if it has been loaded + * @param id - SoundType enum indicating which sound to play + */ @Override public void playSound(SoundType id) { Sound sound = null; @@ -90,6 +94,9 @@ public void playSound(SoundType id) { } } + /** + * Sets the output volume of all sounds that are loaded + */ @Override public void setVolume() { for (var sound: sounds) {