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();



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

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

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



댓글 없음: