package jass.generators; import jass.engine.*; import jass.generators.*; import java.net.*; /** Position based playback of audio date (gramophone model). Wavfile (mono) is indexed with position of needle on record. Every call to getBuffer this UG polls for position of needle in seconds, and uses this with the previous saved value to index a wav file and compute an audio buffer for the corresponding segment. Method to obtain position of needle is abstract. Loads entire clip in memory. @author Kees van den Doel (kvdoel@cs.ubc.ca) */ public abstract class AudioGroove extends Out { /** Buffer with music (groove) */ protected float[] grooveBuffer; /** Buffer length */ protected int grooveBufferLength; /** Sampling rate in Hertz of Out. */ public float srate; /** Sampling rate ratio, srateLoopBuffer/srate */ protected float srateRatio = 1; /** Sampling rate in Hertz of loaded buffer. */ public float srateGrooveBuffer; /** Name of buffer */ protected String name = "x"; /** Current needle position in seconds */ protected double posNeedle=0; /** Past needle position in seconds */ protected double posNeedlePast=0; /** For derived classes @param bufferSize buffer size */ public AudioGroove(int bufferSize) { super(bufferSize); // this is the internal buffer size } /** Construct Groove from named file. @param srate sampling rate in Hertz. @param bufferSize bufferSize of this Out @param fn Audio file name. */ public AudioGroove(float srate,int bufferSize, String fn) { super(bufferSize); // this is the internal buffer size AudioFileBuffer afBuffer = new AudioFileBuffer(fn); grooveBuffer = afBuffer.buf; grooveBufferLength = grooveBuffer.length; srateGrooveBuffer = afBuffer.srate; this.srate = srate; srateRatio = srateGrooveBuffer/srate; this.name = fn; } /** Construct Groove from named URL. @param srate sampling rate in Hertz. @param bufferSize bufferSize of this Out @param url Audio file url name. */ public AudioGroove(float srate,int bufferSize, URL url) { super(bufferSize); // this is the internal buffer size AudioFileBuffer afBuffer = new AudioFileBuffer(url); grooveBuffer = afBuffer.buf; grooveBufferLength = grooveBuffer.length; srateGrooveBuffer = afBuffer.srate; this.srate = srate; srateRatio = srateGrooveBuffer/srate; this.name = url.toString(); } /** Construct Groove and provide buffer at same sampling rate. @param srate sampling rate in Hertz. @param bufferSize bufferSize of this Out. @param grooveBuffer groove buffer. */ public AudioGroove(float srate,int bufferSize, float[] grooveBuffer) { super(bufferSize); // this is the internal buffer size this.grooveBuffer = grooveBuffer; srateGrooveBuffer = this.srate = srate; grooveBufferLength = grooveBuffer.length; } /** Get the groove buffer as array. @return The containing loopbuffer */ public float[] getGrooveBuffer() { return grooveBuffer; } /** @return the position (in seconds) of the needle into the audio data */ public abstract double getPositionOfNeedle(); /** Compute the next buffer. */ public void computeBuffer() { int bufsz = getBufferSize(); posNeedlePast = posNeedle; posNeedle = getPositionOfNeedle(); double ireal; // (fractional) index into grooveBuffer // ireal = a + b * k (k integer index in buffer to compute)a double a = posNeedlePast * srateGrooveBuffer; double b = (posNeedle*srateGrooveBuffer - a)/(bufsz); //System.out.println("p= "+posNeedle+"ppast= "+posNeedlePast); for(int k=0;k<bufsz;k++) { ireal = a + b*(k+1); if(ireal >= grooveBufferLength -1 || ireal < 0) { buf[k] = 0; } else { int i = (int)ireal; // integer part double ifrac = ireal - i; // fractional part buf[k] = (float)((1-ifrac)*grooveBuffer[i] + ifrac*grooveBuffer[i+1]); } } } }