From ca7cd8d5a6e07378bac6ea0cde3c55bd485be74f Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 30 Apr 2025 20:26:47 +0200 Subject: [PATCH] feat: add audio --- .gitignore | 4 +- app/src/main/java/chess/SwingMain.java | 3 + .../java/chess/view/audio/AudioFiles.java | 63 +++++++++++++++++++ .../java/chess/view/audio/AudioPlayer.java | 44 +++++++++++++ .../main/java/chess/view/audio/GameAudio.java | 32 ++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/chess/view/audio/AudioFiles.java create mode 100644 app/src/main/java/chess/view/audio/AudioPlayer.java create mode 100644 app/src/main/java/chess/view/audio/GameAudio.java diff --git a/.gitignore b/.gitignore index 0056fd7..7b727db 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ build app/bin -.vscode \ No newline at end of file +.vscode + +audio/*.wav \ No newline at end of file diff --git a/app/src/main/java/chess/SwingMain.java b/app/src/main/java/chess/SwingMain.java index ab5ce8b..8080711 100644 --- a/app/src/main/java/chess/SwingMain.java +++ b/app/src/main/java/chess/SwingMain.java @@ -8,6 +8,7 @@ import chess.controller.event.GameAdaptator; import chess.model.Color; import chess.model.Game; import chess.pgn.PgnExport; +import chess.view.audio.GameAudio; import chess.view.simplerender.Window; public class SwingMain { @@ -31,6 +32,8 @@ public class SwingMain { } }); + commandExecutor.addListener(new GameAudio()); + commandExecutor.executeCommand(new NewGameCommand()); } } diff --git a/app/src/main/java/chess/view/audio/AudioFiles.java b/app/src/main/java/chess/view/audio/AudioFiles.java new file mode 100644 index 0000000..1b805e2 --- /dev/null +++ b/app/src/main/java/chess/view/audio/AudioFiles.java @@ -0,0 +1,63 @@ +package chess.view.audio; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; + +import chess.view.AssetManager; + +public class AudioFiles { + + private static final String baseURL = "https://images.chesscomfiles.com/chess-themes/sounds/_WAV_/default/"; + private static final String[] files = { "game-start", "game-end", "capture", "castle", "premove", "move-self", + "move-check", "move-opponent", "promote", "notify", "tenseconds", "illegal" }; + private static final String filesExtension = ".wav"; + private static final String saveDir = "audio/"; + + public static boolean initFiles() { + createSaveDir(); + for (String file : files) { + if (!initFile(file + filesExtension)) + return false; + } + return true; + } + + private static boolean downloadFile(String fileName) { + System.out.println("[GameAudio] missing " + fileName + " Downloading ..."); + try (BufferedInputStream in = new BufferedInputStream(new URI(baseURL + fileName).toURL().openStream()); + FileOutputStream fileOutputStream = new FileOutputStream(saveDir + fileName)) { + byte dataBuffer[] = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + return true; + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + return false; + } + } + + private static void createSaveDir() { + new File(saveDir).mkdir(); + } + + private static boolean initFile(String fileName) { + if (isFileDownloaded(saveDir + fileName)) + return true; + return downloadFile(fileName); + } + + private static boolean isFileDownloaded(String fileName) { + return AssetManager.getResource(fileName) != null; + } + + public static InputStream getAudio(String audioName) { + return AssetManager.getResource(saveDir + audioName + filesExtension); + } +} diff --git a/app/src/main/java/chess/view/audio/AudioPlayer.java b/app/src/main/java/chess/view/audio/AudioPlayer.java new file mode 100644 index 0000000..82127b9 --- /dev/null +++ b/app/src/main/java/chess/view/audio/AudioPlayer.java @@ -0,0 +1,44 @@ +package chess.view.audio; + +import java.io.BufferedInputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; + +public class AudioPlayer { + public static void playSound(InputStream audio) { + new Thread(new Runnable() { + // The wrapper thread is unnecessary, unless it blocks on the + // Clip finishing; see comments. + public void run() { + try { + Clip clip = AudioSystem.getClip(); + BufferedInputStream bufferedInputStream = new BufferedInputStream(audio); + AudioInputStream inputStream = AudioSystem.getAudioInputStream(bufferedInputStream); + clip.open(inputStream); + clip.start(); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }).start(); + } + + private static AudioInputStream convertToPCM(AudioInputStream audioInputStream) { + AudioFormat m_format = audioInputStream.getFormat(); + + if ((m_format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) && + (m_format.getEncoding() != AudioFormat.Encoding.PCM_UNSIGNED)) { + AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, + m_format.getSampleRate(), 16, + m_format.getChannels(), m_format.getChannels() * 2, + m_format.getSampleRate(), m_format.isBigEndian()); + audioInputStream = AudioSystem.getAudioInputStream(targetFormat, audioInputStream); + } + + return audioInputStream; + } +} diff --git a/app/src/main/java/chess/view/audio/GameAudio.java b/app/src/main/java/chess/view/audio/GameAudio.java new file mode 100644 index 0000000..cd3fcf7 --- /dev/null +++ b/app/src/main/java/chess/view/audio/GameAudio.java @@ -0,0 +1,32 @@ +package chess.view.audio; + +import chess.controller.event.GameAdaptator; + +public class GameAudio extends GameAdaptator { + + private final boolean functional; + + public GameAudio() { + this.functional = AudioFiles.initFiles(); + if(!this.functional){ + System.err.println("[GameAudio] Failed to initialize audio files. Aborting ..."); + } + } + + private void playSound(String soundName) { + if (!this.functional) + return; + AudioPlayer.playSound(AudioFiles.getAudio(soundName)); + } + + @Override + public void onGameStart() { + playSound("game-start"); + } + + @Override + public void onGameEnd() { + playSound("game-end"); + } + +}