ArkaLlop - Clon del Arkanoid

Llop Site Home > JAVA > ArkaLlop > Música

Música:

Clase LlopClip

package arkallop;

import java.io.*;
import java.net.*;
import java.lang.*;
import javax.sound.sampled.*;

/** Título: ArkaLlop
    Descripción: Prácticas capítulo 11, ejercicio 4
    Copyright: Copyright (c) 2005
    Empresa: Casa_Llop
    @author Albert_Lobo
    @version 1.0 */

/** Clase que permite reproducir continuadamente un archivo de audio en una URL.
    Esta clase, en lugar de cargar todo el archivo en memoria e ir reproduciendo,
    va leyendo de un flujo de audio provinente de la URL.
    Esta clase no está pensada para efectos sonoros, sino para canciones.
    Un efecto sonoro ocupa muy poco, y no cuesta nada cargarlo en memoria -mientras que una canción
    puede ocupar tanto como quiera.
    En mi ordenador, Java no ha podido cargar archivos de audio mayores de 1.5 MB en la clase 'Clip'
    (la que se utiliza para los efectos sonoros).
    El truco de esta clase es ir escribiendo el flujo en un buffer, e ir leyendo de ahí. */
public class LlopClip
{
  // Aquí se encuentra la canción que nos interesa.
  private URL url;
  // El hilo que irá leyendo del flujo.
  private HiloMusical hilo;
  // Variable que indica si la reproducción ha empezado o ya terminó.
  private boolean play;

  /** Constructor. Sólo necesitamos la URL en la que se encuentra la música.
      @param nuevaUrl URL  En esta URL hay el fichero de audio. */
  public LlopClip (URL nuevaUrl)
  {
    url = nuevaUrl;
  }

  /** Inicia la reproducción contínua del clip. */
  public void playClip ()
  {
    // Sonando...
    play = true;
    // Ponemos el hilo a null; a continuación creamos una nueva instancia, y que corra el hilo.
    hilo = null;
    hilo = new HiloMusical ();
    hilo.start ();
  }

  /** Detiene la reproducción del clip. */
  public void stopClip ()
  {
    play = false;
  }

  /** Clase interna. Es el hilo que se encargará de leer el archivo de audio poco a poco. */
  private class HiloMusical extends Thread
  {
    // Flujo de audio que vendrá de la URL.
    private AudioInputStream flujo;
    // El formato de ese flujo de audio.
    private AudioFormat formato;
    // Línea que va pasando el sonido al 'mixer' para que lo saque por los altavoces.
    private SourceDataLine linea;

    /** Constructor. Como si fuera new Thread (). */
    private HiloMusical ()
    {
      super ();
    }

    /** Método que hay que sobrecargar del 'Thread'. Reproduce contínuamente el clip: cuando
        llega al final, vuelve a empezar. Para detener el bucle, hay que poner a 'false' la variable
        de clase 'play'. */
    public void run ()
    {
      // Obtenemos el flujo de entrada de audio de la URL.
      try
      {
        flujo = AudioSystem.getAudioInputStream (url);
      } catch (UnsupportedAudioFileException e) {
      } catch (IOException e) {}

      // Obtenemos la información sobre el formato del flujo.
      formato = flujo.getFormat ();
      // Creamos un objeto 'Line.Info', que nos servirá para crear una línea apropiada para el flujo.
      DataLine.Info info = new DataLine.Info (SourceDataLine.class, formato);

      // Inicializamos la línea por la que reproduciremos el flujo de audio, y la abrimos.
      try
      {
        linea = (SourceDataLine) AudioSystem.getLine (info);
        linea.open (formato);
      } catch (LineUnavailableException e) {}
      // Cuánto ocupa un 'frame' de este archivo de audio.
      int tamanoFrame = formato.getFrameSize ();
      // Creamos un buffer que guardará lo leído del flujo, para que se pueda pasar a la línea.
      // Le damos un tamaño de 4k de 'frames' de audio.
      byte buffer [] = new byte [4 * 1024 * tamanoFrame];

      // Índice para la posición del buffer en la que comenzaremos a escribir.
      int numBytes = 0;
      // Lleva la cuenta de los bytes leídos del flujo a cada vuelta.
      int bytesLeidos = 0;

      while (true)
      {
        // Salimos del bucle cuando 'play' sea 'false'.
        if (!play)
          break;

        // Leemos un poco del flujo, y lo metemos en el buffer.
        try
        {
          bytesLeidos = flujo.read (buffer, numBytes, buffer.length - numBytes);
        } catch (IOException e) {}

        // Cuando ya no quedan bytes para leer, reinicializamos el flujo para volver
        // a empezar la canción.
        if (bytesLeidos == -1)
        {
          numBytes = 0;
          try
          {
            flujo.close ();
            flujo = AudioSystem.getAudioInputStream (url);
            bytesLeidos = flujo.read (buffer, numBytes, buffer.length - numBytes);
          } catch (UnsupportedAudioFileException e) {
          } catch (IOException e) {}
        }

        numBytes += bytesLeidos;

        // Que la línea empiece a sonar.
        linea.start ();

        // Habrá que escribir en el buffer un número de bytes múltiplo del tamaño de un 'frame'.
        int bytesAEscribir = (numBytes / tamanoFrame) * tamanoFrame;

        // Pasamos el contenido del buffer a la línea. Ésta los pasa a su propio buffer y los
        // 'hace sonar' (los pasa al 'mixer').
        // Este método bloquea la ejecución del hilo hasta haber pasado _todos_ los bytes del buffer.
        linea.write (buffer, 0, bytesAEscribir);

        // Si no tenemos un múltiplo del tamaño de un 'frame', copiamos el resto de bytes
        // al principio del buffer.
        int bytesRestantes = numBytes - bytesAEscribir;
          if (bytesRestantes > 0)
            System.arraycopy (buffer, bytesAEscribir, buffer, 0, bytesRestantes);
        numBytes = bytesRestantes;

        // Que descanse el hilo una décima.
        try
        {
          Thread.sleep (100);
        } catch (InterruptedException e) {}
      }

      // Bloqueamos el hilo hasta que haya terminado de sonar el contenido del buffer.
      linea.drain ();
      // Cerramos la línea.
      if (linea != null)
        linea.close ();
    }
  }
}



Clase Sonido

package arkallop;

import java.io.*;
import java.lang.*;
import javax.sound.sampled.*;

/** Esta clase guarda los efectos sonoros y la música de fondo, y proporciona métodos para reproducirlos.
    Si el sonido se carga antes que los hilos, no se les concederá espacio en memoria a todos. */
class Sonido
{
  /** Constante entera con el total de clips de la clase. */
  public static final byte NUMERO_CLIPS = 22;

  /** Constante correspondiente al efecto sonoro de impacto de bola. */
  public static final byte BOLA_IMPACTA = 0;
  /** Constante correspondiente al efecto sonoro de despegue de bola. */
  public static final byte BOLA_DESPEGA = 1;
  /** Constante correspondiente al efecto sonoro de cambio de tamaño de las bolas. */
  public static final byte BONO_TAMANO_BOLA = 2;
  /** Constante correspondiente al efecto sonoro de imantar/desimantar la pala. */
  public static final byte BONO_IMAN = 3;
  /** Constante correspondiente al efecto sonoro de abrir/cerrar la puerta al siguiente nivel. */
  public static final byte BONO_NIVEL = 4;
  /** Constante correspondiente al efecto sonoro de cargar/descargar los cañones en la pala. */
  public static final byte BONO_TIRO = 5;
  /** Constante correspondiente al efecto sonoro de vida extra. */
  public static final byte BONO_VIDA = 6;
  /** Constante correspondiente al efecto sonoro de cambiar el tamaño de la pala. */
  public static final byte BONO_TAMANO_PALA = 7;
  /** Constante correspondiente al efecto sonoro de cargar la pala para un nuevo intento. */
  public static final byte CARGA_PALA = 8;
  /** Constante correspondiente al efecto sonoro de 'game over'. */
  public static final byte GAME_OVER = 9;
  /** Constante correspondiente al efecto sonoro de impacto de tiro. */
  public static final byte IMPACTA_TIRO = 10;
  /** Constante correspondiente al efecto sonoro de 'juego completado'. */
  public static final byte JUEGO_COMPLETO = 11;
  /** Constante correspondiente al efecto sonoro de ladrillo estresado. */
  public static final byte LADRILLO_ESTRESADO = 12;
  /** Constante correspondiente al efecto sonoro de pausar/despausar. */
  public static final byte PAUSA = 13;
  /** Constante correspondiente al efecto sonoro de estallido de alien y bono. */
  public static final byte PETA_BONO_ALIEN = 14;
  /** Constante correspondiente al efecto sonoro de estallido de ladrillo. */
  public static final byte PETA_LADRILLO = 15;
  /** Constante correspondiente al efecto sonoro de estallido de bola. */
  public static final byte PIERDE_VIDA = 16;
  /** Constante correspondiente al efecto sonoro de aparición de un bono. */
  public static final byte SALE_BONO = 17;
  /** Constante correspondiente al efecto sonoro de aparición de un alien. */
  public static final byte SALE_ALIEN = 18;
  /** Constante correspondiente al efecto sonoro de disparo. */
  public static final byte DISPARO = 19;
  /** Constante correspondiente al efecto sonoro de truco introducido. */
  public static final byte TRUCO = 20;
  /** Constante correspondiente al efecto sonoro de acelerar/decelerar las bolas. */
  public static final byte BONO_ACELERA_DECELRA = 21;

  // Tabla de 'Clip's donde se guardan todos los sonoros para el juego.
  private Clip clip [];
  // La música de fondo.
  private LlopClip musicaFondo;

  /** Constructor. Define el clip designado como música de fondo durante la partida.
      @param nuevoClipFondo byte  Clip que sonará de fondo en la partida.  */
  public Sonido (LlopClip nuevaMusicaFondo)
  {
    // Inicializamos todos los clips.
    clip = new Clip [NUMERO_CLIPS];
    for (byte indice = 0; indice < NUMERO_CLIPS; indice++)
      try
      {
        AudioInputStream flujo = ArkaLlop.getFlujoAudio ("clip" + String.valueOf (indice) + ".wav");
        AudioFormat formato = flujo.getFormat ();
        DataLine.Info informacion = new DataLine.Info (Clip.class, flujo.getFormat (),
                                        (int) (flujo.getFrameLength () * formato.getFrameSize ()));
        clip [indice] = (Clip) AudioSystem.getLine (informacion);
        clip [indice].open (flujo);
      } catch (IOException ex) {
      } catch (LineUnavailableException ex) {}
    musicaFondo = nuevaMusicaFondo;
  }

  /** Método que hace sonar uno de los clips desde el principio.
      @param efecto byte  Efecto sonoro -uno de los identificadores constantes de la clase. */
  public void efectoSonoro (byte efecto)
  {
    clip [efecto].setFramePosition (0);
    clip [efecto].start ();
  }

  /** Hace sonar la música de fondo. */
  public void playMusicaFondo ()
  {
    musicaFondo.playClip ();
  }

  /** Detiene la reproducción de la música de fondo. */
  public void stopMusicaFondo ()
  {
    musicaFondo.stopClip ();
  }
}

¿Comentarios, sugerencias?: llopsite.at.yahoo.es | © 2005-07 Albert Lobo

Última actualización: 18-Feb-2007

Hosted by www.Geocities.ws

1