mirror of
https://github.com/processing/processing4.git
synced 2026-02-03 13:49:18 +01:00
working on java 1.1 audio
This commit is contained in:
211
core/PSound.java
211
core/PSound.java
@@ -25,6 +25,7 @@
|
||||
package processing.core;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import sun.audio.*;
|
||||
|
||||
// add check for reflection in host applet for sound completion
|
||||
@@ -32,18 +33,30 @@ import sun.audio.*;
|
||||
|
||||
|
||||
/**
|
||||
* This is the crappy 8 khz ulaw version that's compatible
|
||||
* 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.
|
||||
*/
|
||||
public class PSound {
|
||||
PApplet applet;
|
||||
// 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[];
|
||||
|
||||
|
||||
public PSound() { } // for subclass
|
||||
public PSound() { } // for 1.3 subclass
|
||||
|
||||
|
||||
public PSound(PApplet applet, InputStream input) {
|
||||
this.applet = applet;
|
||||
public PSound(PApplet parent, InputStream input) {
|
||||
this.parent = parent;
|
||||
|
||||
/*
|
||||
try {
|
||||
@@ -52,10 +65,40 @@ public class PSound {
|
||||
error("<init>", e);
|
||||
}
|
||||
*/
|
||||
|
||||
parent.registerDispose(this);
|
||||
|
||||
try {
|
||||
soundEventMethod =
|
||||
parent.getClass().getMethod("soundEvent",
|
||||
new Class[] { PSound.class });
|
||||
|
||||
// if we're here, then it means that there's a method for it
|
||||
/*
|
||||
clip.addLineListener(new LineListener() {
|
||||
public void update(LineEvent event) {
|
||||
if (event.getType() == LineEvent.Type.STOP) {
|
||||
try {
|
||||
soundEventMethod.invoke(parent,
|
||||
new Object[] { PSound.this });
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling soundEvent()");
|
||||
e.printStackTrace();
|
||||
soundEventMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void play() {
|
||||
AudioPlayer.player.start(stream);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +106,7 @@ public class PSound {
|
||||
* either sets repeat flag, or begins playing (and sets)
|
||||
*/
|
||||
public void loop() {
|
||||
loop = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,10 +116,12 @@ public class PSound {
|
||||
* continue to the end of the clip."
|
||||
*/
|
||||
public void noLoop() {
|
||||
loop = false;
|
||||
}
|
||||
|
||||
|
||||
public void pause() {
|
||||
AudioPlayer.player.stop(stream);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +129,8 @@ public class PSound {
|
||||
* Stops the audio and rewinds to the beginning.
|
||||
*/
|
||||
public void stop() {
|
||||
AudioPlayer.player.stop(stream);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +138,8 @@ public class PSound {
|
||||
* current position inside the clip (in seconds, just like video)
|
||||
*/
|
||||
public float time() {
|
||||
return 0;
|
||||
//return 0;
|
||||
return (float)position / (float)SAMPLING_RATE;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +152,7 @@ public class PSound {
|
||||
|
||||
|
||||
public void volume(float v) { // ranges 0..1
|
||||
this.volume = v;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +161,154 @@ public class PSound {
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
protected void error(String where, Exception e) {
|
||||
applet.die("Error inside PSound." + where + "()", 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import javax.sound.sampled.*;
|
||||
// for this class: http://javaalmanac.com/egs/javax.sound.sampled/pkg.html
|
||||
|
||||
public class PSound2 extends PSound {
|
||||
PApplet parent;
|
||||
//PApplet parent;
|
||||
Method soundEventMethod;
|
||||
|
||||
Clip clip;
|
||||
@@ -47,12 +47,11 @@ public class PSound2 extends PSound {
|
||||
AudioInputStream stream =
|
||||
AudioSystem.getAudioInputStream(input);
|
||||
|
||||
// *** this code appears as though it may just be faulty ***
|
||||
|
||||
// At present, ALAW and ULAW encodings must be converted
|
||||
// to PCM_SIGNED before it can be played
|
||||
AudioFormat format = stream.getFormat();
|
||||
if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
|
||||
// *** this code appears as though it may just be faulty ***
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
format.getSampleRate(),
|
||||
format.getSampleSizeInBits()*2,
|
||||
@@ -61,7 +60,7 @@ public class PSound2 extends PSound {
|
||||
format.getFrameRate(),
|
||||
true); // big endian
|
||||
stream = AudioSystem.getAudioInputStream(format, stream);
|
||||
//} else {
|
||||
//} else {
|
||||
//System.out.println("no conversion necessary");
|
||||
}
|
||||
|
||||
@@ -202,6 +201,7 @@ public class PSound2 extends PSound {
|
||||
gainControl.setValue(dB);
|
||||
}
|
||||
|
||||
|
||||
/** mute */
|
||||
/*
|
||||
public void noVolume() {
|
||||
|
||||
Reference in New Issue
Block a user