home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 25 / CDROM25.iso / Share / prog / VJ11 / VJTRIAL.EXE / IE30Java.exe / classd.exe / sun / audio / AudioDevice.java < prev    next >
Encoding:
Java Source  |  1997-01-27  |  11.3 KB  |  408 lines

  1. /*
  2.  * @(#)AudioDevice.java    1.4 96/03/12 Arthur van Hoff, Thomas Ball
  3.  *
  4.  * Copyright (c) 1994, 1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package sun.audio;
  21.  
  22. import java.util.Vector;
  23. import java.util.Enumeration;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27.  
  28. /**
  29.  * This class provides an interface to a Sun audio device.
  30.  *
  31.  * This class emulates systems with multiple audio channels, mixing
  32.  * multiple streams for the workstation's single-channel device.
  33.  *
  34.  * @see AudioData
  35.  * @see AudioDataStream
  36.  * @see AudioStream
  37.  * @see AudioStreamSequence
  38.  * @see ContinuousAudioDataStream
  39.  * @author Arthur van Hoff, Thomas Ball
  40.  * @version     1.2, 23 Aug 1995
  41.  */
  42. public class AudioDevice {
  43.  
  44.     private Vector streams;
  45.     private byte ulaw[];
  46.     private int linear[];
  47.     private int dev;
  48.  
  49.     /*
  50.      * ulaw stuff
  51.      */
  52.     private static final int MSCLICK = 50;
  53.     private static final int MSMARGIN = MSCLICK / 3;
  54.     private static final int BYTES_PER_SAMPLE = 1;
  55.     private static final int SAMPLE_RATE = 8000;
  56.  
  57.     /* define the add-in bias for 16 bit samples */
  58.     private final static int ULAW_BIAS = 0x84;
  59.     private final static int ULAW_CLIP = 32635;
  60.  
  61.     private final static int ULAW_TAB[] = {
  62.     -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
  63.     -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
  64.     -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
  65.     -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
  66.     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
  67.     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
  68.     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
  69.     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
  70.     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
  71.     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
  72.     -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
  73.     -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
  74.     -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
  75.     -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
  76.     -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
  77.     -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
  78.     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
  79.     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
  80.     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
  81.     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
  82.     7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
  83.     5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
  84.     3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
  85.     2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
  86.     1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
  87.     1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
  88.     876,    844,    812,    780,    748,    716,    684,    652,
  89.     620,    588,    556,    524,    492,    460,    428,    396,
  90.     372,    356,    340,    324,    308,    292,    276,    260,
  91.     244,    228,    212,    196,    180,    164,    148,    132,
  92.     120,    112,    104,     96,     88,     80,     72,     64,
  93.         56,     48,     40,     32,     24,     16,      8,      0
  94.     };
  95.     private final static int ULAW_LUT[] = {
  96.     0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  97.     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  98.     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  99.     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  100.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  101.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  102.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  103.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  104.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  105.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  106.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  107.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  108.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  109.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  110.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  111.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
  112.     };
  113.  
  114.     private native int audioOpen();
  115.     private native void audioClose();
  116.     private synchronized native void audioWrite(byte buf[], int len);
  117.  
  118.     /**
  119.      * The default audio player. This audio player is initialized
  120.      * automatically.
  121.      */
  122.     public static final AudioDevice device = new AudioDevice();
  123.  
  124.     /**
  125.      * Create an AudioDevice instance.
  126.      */
  127.     private AudioDevice() {
  128.         try {
  129.         System.loadLibrary("msawt");
  130.         } catch (UnsatisfiedLinkError e) {
  131.             System.out.println("could not find/load the mmedia library");
  132.         }
  133.  
  134.     streams = new Vector();
  135.     int bufferSize = ((SAMPLE_RATE * MSCLICK) / 1000) * BYTES_PER_SAMPLE;
  136.     ulaw = new byte[bufferSize];
  137.     linear = new int[bufferSize];
  138.     }
  139.  
  140.     /**
  141.      *  Open an audio channel.
  142.      */
  143.     public synchronized void openChannel(InputStream in) {
  144.     streams.insertElementAt(in, 0);
  145.     notify();
  146.     }
  147.  
  148.     /**
  149.      *  Close an audio channel.
  150.      */
  151.     public synchronized void closeChannel(InputStream in) {
  152.     if (streams.removeElement(in)) {
  153.         try {
  154.         in.close();
  155.         } catch (IOException e) {
  156.         }
  157.     }
  158.     }
  159.  
  160.     /**
  161.      * Open the device (done automatically)
  162.      */
  163.     public synchronized void open() {
  164.     int    ntries = 1;
  165.     int    maxtries = 5;
  166.     while (dev == 0) {
  167.         dev = audioOpen();
  168.         if (dev < 0) {
  169.         System.out.println("no audio device");
  170.         return;
  171.         }
  172.         if (dev == 0) {
  173.         System.out.println("audio device busy (attempt " + ntries +
  174.                    " out of " + maxtries + ")");
  175.         if ((streams.size() == 0) || (++ntries > maxtries)) {
  176.             // failed to open the device
  177.             // close all open streams, wait a while and return
  178.             closeStreams();
  179.             return;
  180.         }
  181.  
  182.         // use wait instead of sleep because this unlocks the
  183.         // current object during the wait.
  184.         try {
  185.             wait(3000);
  186.         } catch (InterruptedException e) {
  187.             closeStreams();
  188.             return;
  189.         }
  190.         }
  191.     }
  192.     }
  193.  
  194.     /**
  195.      * Close the device (done automatically)
  196.      */
  197.     public synchronized void close() {
  198.     if (dev != 0) {
  199.         audioClose();
  200.         dev = 0;
  201.     }
  202.     closeStreams();
  203.     }
  204.  
  205.     /**
  206.      * Play one mixed click of data
  207.      */
  208.     private synchronized void mix() {
  209.     int len = ulaw.length;
  210.     byte ubuf[] = ulaw;
  211.  
  212.     switch (streams.size()) {
  213.       case 0: {
  214.         // fill the buffer with silence
  215.         for (int n = len ; n-- > 0 ;) {
  216.         ubuf[n] = 127;
  217.         }
  218.         break;
  219.       }
  220.  
  221.       case 1: {
  222.         // read from the input stream
  223.         InputStream in = (InputStream)streams.elementAt(0);
  224.         int n = 0;
  225.         try {
  226.         n = in.read(ubuf, 0, len);
  227.         } catch (IOException e) {
  228.         n = -1;
  229.         }
  230.  
  231.         // Close the stream if needed
  232.         if (n <= 0) {
  233.         streams.removeElementAt(0);
  234.         n = 0;
  235.         try {
  236.             in.close();
  237.         } catch (IOException e) {
  238.         }
  239.         } 
  240.  
  241.         // fill the rest of the buffer with silence
  242.         for (; n < len ; n++) {
  243.         ubuf[n] = 127;
  244.         }
  245.         break;
  246.       }
  247.  
  248.       default: {
  249.         int tab[] = ULAW_TAB;
  250.         int lbuf[] = linear;
  251.         int i = streams.size() - 1;
  252.  
  253.         // fill linear buffer with the first stream
  254.         InputStream in = (InputStream)streams.elementAt(i);
  255.         int n = 0;
  256.         try {
  257.         n = in.read(ubuf, 0, len);
  258.         } catch (IOException e) {
  259.         n = -1;
  260.         }
  261.  
  262.         // Close the stream if needed
  263.         if (n <= 0) {
  264.         streams.removeElementAt(i);
  265.         n = 0;
  266.         try {
  267.             in.close();
  268.         } catch (IOException e) {
  269.         }
  270.         
  271.         }
  272.  
  273.         // copy the data into the linear buffer
  274.         for (int j = 0 ; j < n ; j++) {
  275.         lbuf[j] = tab[ubuf[j] & 0xFF];
  276.         }
  277.  
  278.         // zero the rest of the buffer.
  279.         for (; n < len ; n++) {
  280.         lbuf[n] = 0;
  281.         }
  282.  
  283.         // mix the rest of the streams into the linear buffer
  284.         while (i-- > 0) {
  285.         in = (InputStream)streams.elementAt(i);
  286.         try {
  287.             n = in.read(ubuf, 0, len);
  288.         } catch (IOException e) {
  289.             n = -1;
  290.         }
  291.         if (n <= 0) {
  292.             streams.removeElementAt(i);
  293.             n = 0;
  294.             try {
  295.             in.close();
  296.             } catch (IOException e) {
  297.             }
  298.         }
  299.         while (n-- > 0) {
  300.             lbuf[n] += tab[ubuf[n] & 0xFF];
  301.         }
  302.         }
  303.  
  304.         // convert the linear buffer back to ulaw
  305.         int lut[] = ULAW_LUT;
  306.         for (n = len ; n-- > 0 ; ) {
  307.         int sample = lbuf[n];
  308.  
  309.         /* Get the sample into sign-magnitude. */
  310.         if (sample >= 0) {
  311.             if (sample > ULAW_CLIP) {
  312.             sample = ULAW_CLIP;    /* clip the magnitude */
  313.             }
  314.            
  315.             /* Convert from 16 bit linear to ulaw. */
  316.             sample += ULAW_BIAS;
  317.             int exponent = lut[sample >> 7];
  318.             int mantissa = (sample >> (exponent + 3)) & 0x0F;
  319.             sample = ((exponent << 4) | mantissa) ^ 0xFF;
  320.         } else {
  321.             sample = -sample;
  322.             if (sample > ULAW_CLIP) {
  323.             sample = ULAW_CLIP;    /* clip the magnitude */
  324.             }
  325.             
  326.             /* Convert from 16 bit linear to ulaw. */
  327.             sample += ULAW_BIAS;
  328.             int exponent = lut[sample >> 7];
  329.             int mantissa = (sample >> (exponent + 3)) & 0x0F;
  330.             sample = ((exponent << 4) | mantissa) ^ 0x7F;
  331.         }
  332.         ubuf[n] = (byte)sample;
  333.         }
  334.       }
  335.     }
  336.     
  337.     }
  338.  
  339.     /**
  340.      * Wait for data
  341.      */
  342.     private synchronized boolean waitForData() throws InterruptedException {
  343.     if (streams.size() == 0) {
  344.         close();
  345.         wait();
  346.         open();
  347.         return true;
  348.     }
  349.     return false;
  350.     }
  351.  
  352.     /**
  353.      * Play open audio stream(s)
  354.      */
  355.     public void play() {
  356.     try { 
  357.         long tm = System.currentTimeMillis() - MSMARGIN;
  358.  
  359.         while (dev > 0) {
  360.         // wait for data
  361.         if (waitForData()) {
  362.             tm = System.currentTimeMillis() - MSMARGIN;
  363.         }
  364.  
  365.         // mix the next bit
  366.         mix();
  367.  
  368.         // write the next buffer
  369.         audioWrite(ulaw, ulaw.length);
  370.         
  371.         // wait for the time out
  372.         tm += MSCLICK;
  373.         long delay = tm - System.currentTimeMillis();
  374.         if (delay > 0) {
  375.             Thread.currentThread().sleep(delay);
  376.         } else {
  377.             // We've lost it, reset the time..
  378.             //System.out.println("delay2=" + delay);
  379.             tm = System.currentTimeMillis() - MSMARGIN;
  380.         }
  381.         }
  382.     } catch (InterruptedException e) {
  383.         // the thread got interrupted, exit
  384.     }
  385.     }
  386.     
  387.     /**
  388.      * Close streams
  389.      */
  390.     public synchronized void closeStreams() {
  391.     // close the streams be garbage collected
  392.     for (Enumeration e = streams.elements() ; e.hasMoreElements() ; ) {
  393.         try {
  394.         ((InputStream)e.nextElement()).close();
  395.         } catch (IOException ee) {
  396.         }
  397.     }
  398.     streams = new Vector();
  399.     }
  400.  
  401.     /**
  402.      * Number of channels currently open.
  403.      */
  404.     public int openChannels() {
  405.     return streams.size();
  406.     }
  407. }
  408.