2024년 6월 30일 일요일

2024년 6월 21일 금요일

자바로 사운드, 음악 파일 (wav) 재생 Play sound or music file (wav) with java codes

 대뜸 예제 첨부

일단 아래와 같은 클래스를 만들어 둔다.


import java.io.File;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
/** Class to play wav file */
public class SoundClip implements Serializable
{
  private static final long serialVersionUID = -4189707921602251694L;
  protected URL    url;
    protected double volume = 100.0;
    protected transient boolean flagStop = false;
    /** Create instance with URL to get wav file */
    public SoundClip(URL url)
    {
     this.url = url;
    }
    /** Create instance with wav file */
    public SoundClip(File f) throws MalformedURLException
    {
     this(f.toURI().toURL());
    }
    /** Play wav sound now */
    public void start()
    {
     if(url == null) return;
     flagStop = false;
     AudioInputStream inp1 = null;
     AudioInputStream inp2 = null;
     SourceDataLine   line = null;
     try
     {
     byte[] buffer = new byte[4096];
         int reads;
        
         // Load wav from URL
         inp1 = AudioSystem.getAudioInputStream(url);
    
         if(flagStop) return; // Return when stop() method called
        
         // Detect audio format of wav file and get converted input stream
     AudioFormat formatBase = inp1.getFormat();
     AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, formatBase.getSampleRate(), 16, formatBase.getChannels(), formatBase.getChannels() * 2, formatBase.getSampleRate(), false);
         inp2 = AudioSystem.getAudioInputStream(format, inp1);
        
         if(flagStop) return; // Return when stop() method called
        
         // Create SourceDataLine to play wav
         DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
         Mixer mixer = AudioSystem.getMixer(null);
         line = (SourceDataLine) mixer.getLine(info);
    
     if(flagStop) return; // Return when stop() method called
    
     // Open SourceDataLine
         line.open(format);
        
         // This must be in here (after line opened !)
     FloatControl ctrl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
ctrl.setValue((float) (20.0f * Math.log10(volume / 100.0)));
        
// Play Start
         line.start();
        
         while(! flagStop)
         {
         reads = inp2.read(buffer, 0, buffer.length);
         if(reads < 0) break; // Return when stop() method called
         line.write(buffer, 0, reads);
         }
        
         // END
         line.drain();
         line.stop();
     }
     catch(Exception ex)
     {
     ex.printStackTrace();
     }
     finally
     {
     try { line.close();  } catch(Exception ex) {}
         try { inp2.close();  } catch(Exception ex) {}
         try { inp1.close();  } catch(Exception ex) {}
         flagStop = false;
     }
    }
    /** Play wav sound now */
public void play()
    {
     start();
    }
/** Stop playing */
    public void stop()
    {
     flagStop = true;
    }
    /** Get volume (0 ~ 100) default 100 */
    public double getVolume()
    {
return volume;
    }
    /** Set volume (0 ~ 100) default 100 */
    public void setVolume(double volume)
    {
this.volume = volume;
if(this.volume < 0) this.volume = 0;
    }
    /** Get URL of wav file */
    public URL getUrl() {
        return url;
    }
    /** Set wav file */
    public void setUrl(URL url) {
        this.url = url;
    }
}



이제 이걸 써먹으면 된다.



File file = new File("fire_beam.wav");
new SoundClip(file.toURI().toURL()).play();



문제가 있는데, 사운드를 재생하는 동안 쓰레드를 독차지하고 있게 된다.

즉, 재생하는 동안 그 아래 코드들은 사운드 재생이 끝날 때까지 실행되지 않는다.

그래서 별도 쓰레드를 많이 만들어 두어서 재생 작업을 쓰레드에서 해야 된다.



2024년 6월 16일 일요일

Beton B-Day - The lesser (Beton B-Day 를 더 쉽게 !)

  기존 Beton Brutal 의 DLC Beton Bath 는 너무 난이도가 어려웠습니다.


Beton Brutal

https://store.steampowered.com/app/2330500/BETON_BRUTAL/


이 Beton Brutal 게임은 Custom Map 기능을 제공합니다.
그리하여, Beton B-Day 낙오자들을 위한 커스텀 맵을 만들었습니다.


Beton B-Day - The lesser










플레이 풀 영상


2024년 6월 10일 월요일

Beton Bath - The lesser (Beton Bath 를 더 쉽게 !)

 기존 Beton Brutal 의 DLC Beton Bath 는 너무 난이도가 어려웠습니다.


Beton Brutal

https://store.steampowered.com/app/2330500/BETON_BRUTAL/


Beton Bath DLC




이 Beton Brutal 게임은 Custom Map 기능을 제공합니다.
그리하여, Beton Bath 낙오자들을 위한 커스텀 맵을 만들었습니다.


Beton Bath - The lesser



기존 Beton Bath 의 몇몇 곳에 트랙을 추가하여, 보다 깨기 쉽게 만들었습니다.










플레이 풀 영상 (마이크 설정 실수로 제 목소리가 이상하게 들어간 것 감안해주세요.)


(브랜드 채널이고 라이브 스트리밍 다시보기라 플레이어 첨부가 안되네요.)


Beton B-Day - The Lesser 도 존재합니다.





2024년 6월 9일 일요일

Elgato Wave Neo 세팅 작업 2024.06.09

Elgato Wave Neo 마이크가 도착하였다.

(구매는 https://smartstore.naver.com/grantree/products/10222370399)






전부 종이박스로 되어있고,
옆면을 마치 과자박스인 양 뜯게 되어있다.

구성품을 하나씩 꺼내본다.
박스 여기저기에 구성품들이 숨어있다.





저 본체 옆 좁은 공간에 기둥과 나사들이 숨어있다.




이제 조립을 시작한다.

먼저, 제공된 나사 중 기다란 것부터 조립한다.
한쪽은 그냥 기다랗게만 되어있고, 다른 한쪽이 나사처럼 나선으로 홈 파져있는 부품이 있는데, 그걸 마이크 본체 쪽에 나선쪽 방향을 넣는다. 손으로 돌려서 넣으면 된다.

아래 사진처럼 되면 잘한거다.



기둥을 바닥파트에 꽂는다. 바닥파트에 작은 홈이 삐죽 나와있고, 기둥파트 바닥에도 홈이 들어가는 구멍이 있다.


남은 나사를 바닥파트 뒷면으로 넣어 돌려서 넣는다.
다 넣으면 손잡이 부분은 옆으로 눌러넣으면 된다.



이제 본체를 기둥파트에 꽂는다. 얘도 저 튀어나온 홈 부분이 들어가는 방향이 정해져 있다.






제공된 USB 케이블을 꽂는다. (아직 PC에 꽂기 전이다. PC에 아직 꽂으면 안 된다.)
꽂는 것도 위아래 방향이 정해져 있다.


이제 소프트웨어를 다운로드 받는다.




WAVE LINK 프로그램을 다운로드 받아 설치한다.


이제 소리가 안들릴 텐데,

게시들 들어가서 제어판 소리 설정과 Voicemeeter Banana 설정을 다시 잡는다.
제어판의 경우 마찬가지로 Voicemeeter Input 과 Voicemeeter Out B3 을 기본 장치로 잡으면 된다.




Voicemeeter Banana 의 경우, 마이크만 잡아주면 된다.
저 Stereo Input 1 부분을 그냥 클릭한다.


Mic in 선택.
(작은 글씨로 Elgato Wave Neo 라고 뜬다.)



이것으로 세팅 끝.