
// PlayClip.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Načte zvuková soubor jako klip a přehraj pouze jednou.
   Během přehrávání bude aplikace spát.

   Ukončení klipu způsobí volání metody update(), 
   která ukončí program.

   Změny 6. sprna 2004
     - měření doby trvání klipu pomocí getMicrosecondLength() v metodě loadClip()
     - uzavřen vstupní proud v metodě loadClip()

   Změny 16. září 2004
     - bug: má-li soubor typu WAV méně jak 1 sekundu, 
            nic se nepřehraje. Viz
            http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5085008

     Dvě možná řešení: 

     1) upravit zvuk aby byl dělší jak 1 sekunda
        Voláme metodu checkDuration() třídy loadClip() pro ověření, 
        že trvání klipu není menší než 1 sekunda

     2) přehrávat cyklicky, dokud neuběhne alespoň 1 sekunda.
        To implementujeme v aplikaci PlayClipBF

*/

import java.io.*;
import javax.sound.sampled.*;
import java.text.DecimalFormat;



public class PlayClip implements LineListener
{
  private final static String SOUND_DIR = "Sounds/";

  private Clip clip = null;
  private DecimalFormat df; 



  public PlayClip(String fnm)
  {
    df = new DecimalFormat("0.#");  // 1 dm

    loadClip(SOUND_DIR + fnm);
    play();

    // posečkej, až zvuk dohraje; jeho délku odhadujeme max. na 10 minut!
    System.out.println("Waiting");
    try { 
      Thread.sleep(600000);   // 10 minut v milisekundách
    } 
    catch(InterruptedException e) 
    { System.out.println("Spánek byl přerušen"); }
  } // konec metody: PlayClip()


  private void loadClip(String fnm)
  {
    try {
      // připoj zvukový proud k souboru s audio-klipem
      AudioInputStream stream = AudioSystem.getAudioInputStream(
                          getClass().getResource(fnm) );

      AudioFormat format = stream.getFormat();

      // převeď data ve formátu ULAW/ALAW do formátu PCM
      if ( (format.getEncoding() == AudioFormat.Encoding.ULAW) ||
           (format.getEncoding() == AudioFormat.Encoding.ALAW) ) {
        AudioFormat newFormat = 
           new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                format.getSampleRate(),
                                format.getSampleSizeInBits()*2,
                                format.getChannels(),
                                format.getFrameSize()*2,
                                format.getFrameRate(), true);  // způsob uložení dat: big endian
        // aktualizuj podrobné údaje ohledně datového proudu a formátu
        stream = AudioSystem.getAudioInputStream(newFormat, stream);
        System.out.println("Převedený audio formát" + newFormat);
        format = newFormat;
      }

      DataLine.Info info = new DataLine.Info(Clip.class, format);

      // ujisti se, že zvukový systém podporuje datové linky
      if (!AudioSystem.isLineSupported(info)) {
        System.out.println("Nepodporovaný formát souboru: " + fnm);
        System.exit(0);
      }

      // získej zdroj linky klipu 
      clip = (Clip) AudioSystem.getLine(info);

      // naslouchej událostem klipu
      clip.addLineListener(this);

      clip.open(stream);    // otevři zvukový soubor jako klip
      stream.close(); // se vstupním proudem jsme skončili  // nový

      clip.setFramePosition(0);
      // clip.setMicrosecondmosition(0);

      checkDuration();
    } // konec metody: try block

    catch (UnsupportedAudioFileException audioException) {
      System.out.println("Nepodporovaný zvukový soubor: " + fnm);
      System.exit(0);
    }
    catch (LineUnavailableException noLineException) {
      System.out.println("Zvuková linka není k dispozici : " + fnm);
        System.exit(0);
    }
    catch (IOException ioException) {
      System.out.println("Nemohu přečíst soubor: " + fnm);
      System.exit(0);
    }
    catch (Exception e) {
      System.out.println("Problém s " + fnm);
      System.exit(0);
    }
  } // konec metody: loadClip()


  private void checkDuration()
  {
    // délka klipu (v sekundách)
	double duration = clip.getMicrosecondLength()/1000000.0;  // new
    if (duration <= 1.0) {
      System.out.println("WARNING. Duration <= 1 sekunda : " + df.format(duration) + " sekund");
      System.out.println("         Je možné, že nedojde v J2SE 1.5 nedojde k přehrátí -- zvětšete jej");
    }
    else
      System.out.println("Délka: " + df.format(duration) + " sekund");
  }  // konec metody: checkDuration()


  private void play()
  { if (clip != null) {
      System.out.println("Playing...");
      clip.start();   // spusť přehrávání
    }
  }


  public void update(LineEvent lineEvent)
  // volá se, když linka klipu detekuje událost otevření, uzavření, začátku či konce
  {
    // došel klip na konec?
    if (lineEvent.getType() == LineEvent.Type.STOP) {
      System.out.println("Končím...");
      clip.stop();
      clip.setFramePosition(0);

      lineEvent.getLine().close();
      System.exit(0);
    }
  } // konec metody: update()

  // --------------------------------------------------

  public static void main(String[] args)
  {
    if (args.length != 1) {
      System.out.println("Použití: java PlayClip <soubor se klipem>");
      System.exit(0);
    }
    new PlayClip(args[0]);
    System.exit(0);    // do J2SE 1.4.2. musíme program ukončit explicitně
  } // konec metody: main()

} // konec třídy: PlayClip
