Files
processing4/core/PSound.java
2005-04-17 15:48:05 +00:00

287 lines
6.8 KiB
Java
Executable File

/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2005 Ben Fry and Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
import java.io.*;
import java.lang.reflect.*;
import sun.audio.*;
/**
* This is the crappy 8 khz mono ulaw version that's compatible
* with Java 1.1 and 1.2. For Java 1.3 and higher, PSound2 is used.
* <P>
* This code currently does not work, but PSound2 sort of does.
*/
public class PSound {
// supposedly this is actually 8012.8210513 according to spec
public static final int SAMPLING_RATE = 8000;
PApplet parent;
Method soundEventMethod;
InputStream stream;
boolean loop;
float volume = 1;
//int length;
int position;
int data[]; // 16 bit, from -32768 to +32767
public PSound() { } // for 1.3 subclass
public PSound(PApplet parent, InputStream input) {
this.parent = parent;
parent.registerDispose(this);
try {
soundEventMethod =
parent.getClass().getMethod("soundEvent",
new Class[] { PSound.class });
} catch (Exception e) {
// no such method, or an error.. which is fine, just ignore
}
}
public void play() {
AudioPlayer.player.start(stream);
}
/**
* either sets repeat flag, or begins playing (and sets)
*/
public void loop() {
loop = true;
}
/**
* ala java 1.3 loop docs:
* "any current looping should cease and playback should
* continue to the end of the clip."
*/
public void noLoop() {
loop = false;
}
public void pause() {
AudioPlayer.player.stop(stream);
}
/**
* Stops the audio and rewinds to the beginning.
*/
public void stop() {
AudioPlayer.player.stop(stream);
}
/**
* current position inside the clip (in seconds, just like video)
*/
public float time() {
//return 0;
return (float)position / (float)SAMPLING_RATE;
}
/**
* duration of the clip in seconds
*/
public float duration() {
return 0;
}
public void volume(float v) { // ranges 0..1
this.volume = v;
}
/**
* General error reporting, all corraled here just in case
* I think of something slightly more intelligent to do.
*/
protected void error(String where, Exception e) {
parent.die("Error inside PSound." + where + "()", e);
//e.printStackTrace();
}
// ------------------------------------------------------------
class Stream extends InputStream {
int index;
public int available() throws IOException {
return data.length - position;
}
public void close() throws IOException { }
public synchronized void mark() { }
public boolean markSupported() {
return false;
}
public int read() throws IOException {
return 0;
}
public int read(byte b[]) throws IOException {
return 0;
}
public int read(byte b[], int off, int len) throws IOException {
return 0;
}
public synchronized void reset() {
position = 0;
}
public long skip(long n) {
position = (position + (int)n) % data.length;
return n;
}
}
// ------------------------------------------------------------
// Conversion
// ulaw from http://www-svr.eng.cam.ac.uk/comp.speech/Section2/Q2.7.html
static final short BIAS = 0x84;
static final int CLIP = 32635;
static final int[] LINEAR_LUT = {
0, 132, 396, 924, 1980, 4092, 8316, 16764
};
static final int[] LAW_LUT = {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
/**
* 16 bit linear to 8 bit ulaw
*/
static byte linear2ulaw(int linear) {
//int sign, exponent, mantissa;
//byte ulaw;
if (linear > 32767) {
linear = 32767;
} else if(linear < -32768) {
linear = -32768;
}
int sign = linear >> 8 & 0x80;
if (sign != 0) linear = -linear;
if (linear > CLIP) linear = CLIP;
linear += BIAS;
int exponent = LAW_LUT[linear >> 7 & 0xFF];
int mantissa = linear >> exponent + 3 & 0xf;
byte ulaw = (byte) ( ~(sign | exponent << 4 | mantissa));
if (ulaw == 0) ulaw = 2; // CCITT trap
return ulaw;
}
/**
* 8 bit ulaw to 16 bit linear
*/
static int ulaw2linear(int ulaw) {
ulaw = ~ulaw;
int sign = ulaw & 0x80;
int exponent = (ulaw >> 4) & 7;
int mantissa = ulaw & 0x0F;
int linear = LINEAR_LUT[exponent] + (mantissa << exponent + 3);
return (short) ((sign != 0) ? -linear : linear);
}
/**
* cheap resampling with pitch distortion and aliasing
*/
static int[] resample(int original[], int oldfreq, int newfreq) {
int resampled[] = null;
float factor = 0;
int newlength;
if (oldfreq > newfreq) { // downsample
factor = (float)oldfreq / (float)newfreq;
newlength = (int)(original.length / factor);
resampled = new int[newlength];
for (int i = 0; i < newlength; i++) {
resampled[i] = original[(int)(i * factor)];
}
return resampled;
} else if (oldfreq < newfreq) { // upsample (is it necesary??)
factor = (float)newfreq / (float)oldfreq;
newlength = (int) (original.length * factor);
resampled = new int[newlength];
for (int i = 0; i < newlength; i++) {
resampled[i] = original[(int) (i * factor)];
}
return resampled;
}
return original;
}
}