diff options
author | Hans-Christoph Steiner <eighthave@users.sourceforge.net> | 2008-03-22 02:15:12 +0000 |
---|---|---|
committer | Hans-Christoph Steiner <eighthave@users.sourceforge.net> | 2008-03-22 02:15:12 +0000 |
commit | a764e59e1d3a8e330f0d484fdb26b35ca3f0b2e4 (patch) | |
tree | c4ecadccdecf2809b99c0da0545f255a6ad25bb5 /src/java/com/cycling74/msp |
bringing pdj-0.8.3 into the main branchsvn2git-root
svn path=/trunk/externals/loaders/pdj/; revision=9621
Diffstat (limited to 'src/java/com/cycling74/msp')
-rw-r--r-- | src/java/com/cycling74/msp/AudioFileBuffer.java | 116 | ||||
-rw-r--r-- | src/java/com/cycling74/msp/MSPBuffer.java | 127 | ||||
-rw-r--r-- | src/java/com/cycling74/msp/MSPObject.java | 163 | ||||
-rw-r--r-- | src/java/com/cycling74/msp/MSPPerformable.java | 17 | ||||
-rw-r--r-- | src/java/com/cycling74/msp/MSPPerformer.java | 36 | ||||
-rw-r--r-- | src/java/com/cycling74/msp/MSPSignal.java | 70 | ||||
-rw-r--r-- | src/java/com/cycling74/msp/package.html | 5 |
7 files changed, 534 insertions, 0 deletions
diff --git a/src/java/com/cycling74/msp/AudioFileBuffer.java b/src/java/com/cycling74/msp/AudioFileBuffer.java new file mode 100644 index 0000000..b2e76f3 --- /dev/null +++ b/src/java/com/cycling74/msp/AudioFileBuffer.java @@ -0,0 +1,116 @@ +package com.cycling74.msp; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +import com.cycling74.max.MessageReceiver; + +/** + * Work in progress, target: 0.8.4 + */ +class AudioFileBuffer { + + /** file buffer value */ + public float buf[][]; + + /** Value of the message that will be sended to MessageReceiver when the file will be loaded */ + public static final int FINISHED_READING = 1; + + private MessageReceiver callback = null; + private String file; + private AudioFormat audioFormat; + private AudioFormat targetAudioFormat; + + // getters values + private float sampleRate; + private int sampleBitFormat; + private boolean sampleBigEndian; + private int sampleChannels; + private long sampleFrames; + + public AudioFileBuffer(String filename) throws FileNotFoundException, IOException, UnsupportedAudioFileException { + open(filename); + } + + public AudioFileBuffer(String filename, MessageReceiver callback) throws FileNotFoundException, IOException, UnsupportedAudioFileException { + this.callback = callback; + open(filename); + } + + public void open(String filename) throws FileNotFoundException, IOException, UnsupportedAudioFileException { + // file format + sampleRate = 0; + sampleBitFormat = 0; + sampleChannels = 0; + sampleFrames = 0; + + AudioInputStream sourceAudioInputStream = AudioSystem.getAudioInputStream( new FileInputStream(file) ); + AudioFormat sourceAudioFormat = sourceAudioInputStream.getFormat(); + targetAudioFormat = new AudioFormat( + AudioFormat.Encoding.PCM_UNSIGNED, // Encoding + getSystemSampleRate(), // Sample rate + 16, // bit + sourceAudioFormat.getChannels(), // channel + sourceAudioFormat.getFrameSize(), // frame size + sourceAudioFormat.getFrameRate(), // frame rate + false ); // big Endian + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(audioFormat, sourceAudioInputStream ); + + FileLoader thread = new FileLoader(audioInputStream); + new Thread(thread).start(); + } + + class FileLoader implements Runnable { + AudioInputStream ais; + + FileLoader(AudioInputStream input) { + ais = input; + } + + public void run() { + try { + buf = new float[audioFormat.getChannels()][]; + + for (int i=0;ais.available() != 0;i++) { + //doc.content[i] = audioInputStream.read() / 65535; + } + + if ( callback != null ) + callback.messageReceived(this, FINISHED_READING, null); + } catch ( IOException e ) { + } + } + } + + public float getSampleRate() { + return sampleRate; + } + + public int getSampleSizeInBits() { + return sampleBitFormat; + } + + public boolean isBigEndian() { + return sampleBigEndian; + } + + public long getFrameLength() { + return sampleFrames; + } + + public int getChannels() { + return sampleChannels; + } + + public float getLengthMs() { + return buf[0].length / (sampleRate / 1000); + } + + private native int getSystemSampleRate(); +}
\ No newline at end of file diff --git a/src/java/com/cycling74/msp/MSPBuffer.java b/src/java/com/cycling74/msp/MSPBuffer.java new file mode 100644 index 0000000..70b730a --- /dev/null +++ b/src/java/com/cycling74/msp/MSPBuffer.java @@ -0,0 +1,127 @@ +package com.cycling74.msp; + +/** + * Used to get or set pd array content. Please note that the channel parameter + * is added in the API to match Max/MSP MSPBuffer signature. + */ +public class MSPBuffer { + /** + * Returns the array content. + * @param name the array name + * @return the array contents + */ + public static float[] peek(String name) { + return getArray(name, 0, -1); + } + + /** + * Returns the array content. + * @param name the array name + * @param channel <i>not used in pd</i> + * @return the array contents + */ + public static float[] peek(String name, int channel) { + return getArray(name, 0, -1); + } + + /** + * Returns the array content. + * @param name the array name + * @param channel <i>not used in pd</i> + * @param start the start index of the array + * @param length the size of the array to return + * @return the array contents + */ + public static float[] peek(String name, int channel, long start, long length) { + return getArray(name, start, length); + } + + /** + * Returns the array content value at a specific position. + * @param name the array name + * @param channel <i>not used in pd</i> + * @param index the start index of the array + * @return the value stored at index <code>start</code> + */ + public static float peek(String name, int channel, long index) { + float ret[] = getArray(name, index, 1); + if ( ret == null ) + return 0; + return ret[0]; + } + + /** + * Sets array content. + * @param name the array name + * @param values the array to set + */ + public static void poke(String name, float values[]) { + setArray(name, 0, values); + } + + /** + * Sets array content. + * @param name the array name + * @param channel <i>not used in pd</i> + * @param values the array to set + */ + public static void poke(String name, int channel, float values[]) { + setArray(name, 0, values); + } + + /** + * Sets array content. + * @param name the array name + * @param channel <i>not used in pd</i> + * @param start the start index of the array + * @param values the array to set + */ + public static void poke(String name, int channel, long start, float values[]) { + setArray(name, start, values); + } + + /** + * Set a value in a array. + * @param name the array name + * @param channel <i>not used in pd</i> + * @param index the index in the array to set + * @param value the value to set in the array + */ + public static void poke(String name, int channel, long index, float value) { + float content[] = new float[1]; + content[0] = value; + setArray(name, index, content); + } + + /** + * Sets the array size. + * @param name the array name + * @param numchannel <i>not used in pd</i> + * @param size the new array size; + */ + public static native void setSize(String name, int numchannel, long size); + + /** + * Returns the array size + * @param name the array name + * @return the array size or -1 if not found + */ + public static native long getSize(String name); + + private static native float[] getArray(String name, long from, long size); + private static native void setArray(String name, long from, float[]content); + private MSPBuffer() {} + + /** + * Return the number of channel for this array. Useless in PD cause there + * is no channels in a array. + * @param name array name. + * @return always returns 1 on pd; unless the name is not defined. + */ + public static int getChannel(String name) { + // resolv the name + if ( getSize(name) != -1 ) + return 1; + return -1; + } +} diff --git a/src/java/com/cycling74/msp/MSPObject.java b/src/java/com/cycling74/msp/MSPObject.java new file mode 100644 index 0000000..be2d68b --- /dev/null +++ b/src/java/com/cycling74/msp/MSPObject.java @@ -0,0 +1,163 @@ +package com.cycling74.msp; + +import java.lang.reflect.Method; + +import com.cycling74.max.DataTypes; +import com.cycling74.max.MaxObject; + +/** + * Main object to extend to use dsp with pd. You will need to + * use the pdj~ external if you want to process signals. Before + * the dsp starts processing, the method dsp will be called and it must + * return the performer method that will process each dsp cycles. + * + * <p>Here is a basic guideline for using the MSPObject:</p> + * <p><blockquote><pre> + * import com.cycling74.max.*; + * import com.cycling74.msp.*; + * import java.lang.reflection.Method; + * + * public class panner extends MSPObject { + * float left = 1, right = 1; + * + * public panner() { + * declareInlets( new int[] { SIGNAL, DataTypes.ANYTHING } ); + * declareOutlets( new int[] { SIGNAL, SIGNAL } ); + * } + * + * // From 0..127 + * public void inlet(float val) { + * if ( val > 64 ) { + * right = 1; + * left = ((127-val) / 64); + * } else { + * left = 1; + * right = val / 64; + * } + * } + * + * public Method dsp(MSPSignal[] ins, MSPSignal[] outs) { + * return getPerformMethod("perform"); + * } + * + * public void perform(MSPSignal[] ins, MSPSignal[] outs) { + * for (int i=0;i<ins[0].n;i++) { + * outs[0].vec[i] = ins[0].vec[i] * left; + * outs[1].vec[i] = ins[0].vec[i] * right; + * } + * } + * } + * </p></blockquote></pre> + */ +public abstract class MSPObject extends MaxObject { + /** + * Use this value to indentify a signal intlet/outlet to + * the method declareInlet/declareOutlet. + */ + public final static int SIGNAL = 32; + + /** + * Initialize the dsp state. From the numbers of input/output this + * method must return a performing method. + * @param ins input signals + * @param outs output signals + * @return the method to execute at each dsp cycle + */ + public abstract Method dsp(MSPSignal[] ins, MSPSignal[] outs); + + /** + * Quicky method to be used with dsp(MSPSignal[], MSPSignal[]). It + * will return the method name <code>methodName</code> with signature + * (MSPSignal[], MSPSignal[]) in the current class. + * @param methodName the name of the method in the current class + * @return the method reflection + */ + protected Method getPerformMethod(String methodName) { + try { + Method m = getClass().getDeclaredMethod(methodName, new Class[] { + MSP_SIGNAL_ARRAY_CLZ, MSP_SIGNAL_ARRAY_CLZ }); + return m; + } catch ( NoSuchMethodException e ) { + error("pdj~: method: " + methodName + " not found in class in:" + getClass().toString()); + } + return null; + } + + /** + * Force to copy of each MSPBuffer when performer is called. Right now, + * on pdj the MSPBuffer is always copied. + * @param copyBuffer true if you need to copyBuffer + */ + protected void setNoInPlace(boolean copyBuffer) { + //this.copyBuffer = copyBuffer; + } + + /** + * This method is called when the dsp is start/stop. + * <b>NOT USED ON PD.</b> + * @param dspRunning true if the dsp is running + */ + protected void dspstate(boolean dspRunning) { + } + + + /** + * Declare the inlets used by this object. Use MSPObject.SIGNAL + * to define a signal inlet. <b>Note:</b> any signal inlet won't + * be able to process any atom messages. + */ + protected void declareInlets(int[] types) { + int i, inlets = 0; + for (i=0;i<types.length;i++) { + if ( types[i] == SIGNAL ) + inlets++; + } + _used_inputs = new MSPSignal[inlets]; + for(i=0;i<_used_inputs.length;i++) { + _used_inputs[i] = new MSPSignal(); + } + super.declareInlets(types); + } + + /** + * Declare the outlets used by this object. Use MSPObject.SIGNAL + * to define a signal outlet. + */ + protected void declareOutlets(int[] types) { + int i, outlets = 0; + for (i=0;i<types.length;i++) { + if ( types[i] == SIGNAL ) + outlets++; + } + _used_outputs = new MSPSignal[outlets]; + for(i=0;i<_used_outputs.length;i++) { + _used_outputs[i] = new MSPSignal(); + } + super.declareOutlets(types); + } + + public static final Class MSP_SIGNAL_ARRAY_CLZ = (new MSPSignal[0]).getClass(); + + private MSPSignal[] _used_inputs = new MSPSignal[0]; + private MSPSignal[] _used_outputs = new MSPSignal[0]; + + private Method _dspinit(float sr, int vector_size) { + int i; + for(i=0;i<_used_inputs.length;i++) { + _used_inputs[i].n = vector_size; + _used_inputs[i].vec = new float[vector_size]; + _used_inputs[i].sr = sr; + } + for(i=0;i<_used_outputs.length;i++) { + _used_outputs[i].n = vector_size; + _used_outputs[i].vec = new float[vector_size]; + _used_outputs[i].sr = sr; + } + dspstate(true); + return dsp(_used_inputs, _used_outputs); + } + + private void _emptyPerformer(MSPSignal[] ins, MSPSignal[] outs) { + } +} + diff --git a/src/java/com/cycling74/msp/MSPPerformable.java b/src/java/com/cycling74/msp/MSPPerformable.java new file mode 100644 index 0000000..6f27241 --- /dev/null +++ b/src/java/com/cycling74/msp/MSPPerformable.java @@ -0,0 +1,17 @@ +package com.cycling74.msp; + +/** + * This interface is used to chain Java dsp objects since they don't + * have to be MSPObject to process signals. + */ +public interface MSPPerformable { + /** + * @see MSPPerformer.dspsetup(MSPSignal in[], MSPSignal out[]) + */ + public void dspsetup(MSPSignal in[], MSPSignal out[]); + + /** + * @see MSPPerformer.perform(MSPSignal in[], MSPSignal out[]); + */ + public void perform(MSPSignal in[], MSPSignal out[]); +} diff --git a/src/java/com/cycling74/msp/MSPPerformer.java b/src/java/com/cycling74/msp/MSPPerformer.java new file mode 100644 index 0000000..2201d82 --- /dev/null +++ b/src/java/com/cycling74/msp/MSPPerformer.java @@ -0,0 +1,36 @@ +package com.cycling74.msp; + +import java.lang.reflect.Method; + +/** + * Process signals with a single method. Like MSPObject except that + * the performer method will always be "perform" (and you override it). + */ +public abstract class MSPPerformer extends MSPObject implements MSPPerformable { + + /** + * Called by PD with the dsp message is sended. This method will then + * call dspsetup and map the method "perform" has the performer method. + * You don't have to override this method, use dspsetup if initialization + * needs to be done before the signals starts processing. + */ + public Method dsp(MSPSignal[] in, MSPSignal[] out) { + dspsetup(in, out); + return getPerformMethod("perform"); + } + + /** + * Initialize the dsp state of the MSPPerformable. Override this if + * you have to initalize something before the signal starts + * processing. + */ + public void dspsetup(MSPSignal[] in, MSPSignal[] out) { + } + + /** + * Process signal inlets/outlets. You must override this since it is + * the main processing method. + */ + public abstract void perform(MSPSignal[] in, MSPSignal[] out); + +} diff --git a/src/java/com/cycling74/msp/MSPSignal.java b/src/java/com/cycling74/msp/MSPSignal.java new file mode 100644 index 0000000..0fb9635 --- /dev/null +++ b/src/java/com/cycling74/msp/MSPSignal.java @@ -0,0 +1,70 @@ +package com.cycling74.msp; + +/** + * Signals representation; signals inlets will copy signal data to this + * object. + */ +public class MSPSignal { + + /** + * Tells the number of time this signal is connected. This is always + * 1 in pure-data. + */ + public short cc = 1; + + /** + * Tells if this signal is connected. This is always true in pure-data. + */ + public boolean connected = true; + + /** + * Number of sample in vector. + */ + public int n; + + /** + * The sampling rate. + */ + public double sr; + + /** + * The current sample data. + */ + public float[] vec; + + MSPSignal() { + } + + public MSPSignal(float vec[], double sr, int n, short cc) { + this.vec = vec; + this.sr = sr; + this.n = n; + this.cc = cc; + } + + /** + * Returns a copy of this signal but with the same sample buffer. + * @return the new signal with the same buffer + */ + public MSPSignal alias() { + return new MSPSignal(vec, sr, n, cc); + } + + /** + * Returns the a duplicated signal object. Also copies the array. + * @return the new signal with the same value + */ + public MSPSignal dup() { + return new MSPSignal((float [])vec.clone(), sr, n, cc); + } + + /** + * Returns the a duplicated signal object, but the sample vector is + * re-initialized. + * @return the new signal with empty value (silence) + */ + public MSPSignal dupclean() { + return new MSPSignal(new float [vec.length], sr, n, cc); + } + +} diff --git a/src/java/com/cycling74/msp/package.html b/src/java/com/cycling74/msp/package.html new file mode 100644 index 0000000..17f4051 --- /dev/null +++ b/src/java/com/cycling74/msp/package.html @@ -0,0 +1,5 @@ +<html> +<body> +<p>Package for using using array and signals objects.</p> +</body> +</html>
\ No newline at end of file |