Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. //The MIT License (MIT)
  2.  
  3. //Copyright (c) 2013 Mick Grierson, Matthew Yee-King, Marco Gillies
  4.  
  5. //Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
  6. //The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
  7.  
  8. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
  9.  
  10. import java.util.ArrayList;
  11. import java.io.File;
  12. import java.io.FileInputStream;
  13. import java.io.FileNotFoundException;
  14. import java.io.IOException;
  15. import java.io.BufferedInputStream;
  16. import java.net.MalformedURLException;
  17. import java.net.URL;
  18. import javax.sound.sampled.AudioFormat;
  19. import javax.sound.sampled.AudioSystem;
  20. import javax.sound.sampled.DataLine;
  21. import javax.sound.sampled.LineUnavailableException;
  22. import javax.sound.sampled.SourceDataLine;
  23.  
  24. import processing.core.*;
  25. import processing.data.*;
  26. import processing.event.*;
  27. import processing.opengl.*;
  28.  
  29. //import android.content.res.Resources;
  30. // import android.app.Activity;
  31. // import android.os.Bundle;
  32. // import android.media.*;
  33. // import android.media.audiofx.Visualizer;
  34. // import android.content.res.AssetFileDescriptor;
  35. // import android.hardware.*;
  36.  
  37.  
  38. public class Maxim {
  39.  
  40.   private float sampleRate;
  41.  
  42.   public final float[] mtof = {
  43.     0f, 8.661957f, 9.177024f, 9.722718f, 10.3f, 10.913383f, 11.562325f, 12.25f, 12.978271f, 13.75f, 14.567617f, 15.433853f, 16.351599f, 17.323914f, 18.354048f, 19.445436f, 20.601723f, 21.826765f, 23.124651f, 24.5f, 25.956543f, 27.5f, 29.135235f, 30.867706f, 32.703197f, 34.647827f, 36.708096f, 38.890873f, 41.203445f, 43.65353f, 46.249302f, 49.f, 51.913086f, 55.f, 58.27047f, 61.735413f, 65.406395f, 69.295654f, 73.416191f, 77.781746f, 82.406891f, 87.30706f, 92.498604f, 97.998856f, 103.826172f, 110.f, 116.540939f, 123.470825f, 130.81279f, 138.591309f, 146.832382f, 155.563492f, 164.813782f, 174.61412f, 184.997208f, 195.997711f, 207.652344f, 220.f, 233.081879f, 246.94165f, 261.62558f, 277.182617f, 293.664764f, 311.126984f, 329.627563f, 349.228241f, 369.994415f, 391.995422f, 415.304688f, 440.f, 466.163757f, 493.883301f, 523.25116f, 554.365234f, 587.329529f, 622.253967f, 659.255127f, 698.456482f, 739.988831f, 783.990845f, 830.609375f, 880.f, 932.327515f, 987.766602f, 1046.502319f, 1108.730469f, 1174.659058f, 1244.507935f, 1318.510254f, 1396.912964f, 1479.977661f, 1567.981689f, 1661.21875f, 1760.f, 1864.655029f, 1975.533203f, 2093.004639f, 2217.460938f, 2349.318115f, 2489.015869f, 2637.020508f, 2793.825928f, 2959.955322f, 3135.963379f, 3322.4375f, 3520.f, 3729.31f, 3951.066406f, 4186.009277f, 4434.921875f, 4698.63623f, 4978.031738f, 5274.041016f, 5587.651855f, 5919.910645f, 6271.926758f, 6644.875f, 7040.f, 7458.620117f, 7902.132812f, 8372.018555f, 8869.84375f, 9397.272461f, 9956.063477f, 10548.082031f, 11175.303711f, 11839.821289f, 12543.853516f, 13289.75f
  44.   };
  45.  
  46.   private AudioThread audioThread;
  47.   private PApplet processing;
  48.  
  49.   public Maxim (PApplet processing) {
  50.     this.processing = processing;
  51.     sampleRate = 44100f;
  52.     audioThread = new AudioThread(sampleRate, 4096, false);
  53.     audioThread.start();
  54.   }
  55.  
  56.   public float[] getPowerSpectrum() {
  57.     return audioThread.getPowerSpectrum();
  58.   }
  59.  
  60.   /**
  61.    *  load the sent file into an audio player and return it. Use
  62.    *  this if your audio file is not too long want precision control
  63.    *  over looping and play head position
  64.    * @param String filename - the file to load
  65.    * @return AudioPlayer - an audio player which can play the file
  66.    */
  67.   public AudioPlayer loadFile(String filename) {
  68.     // this will load the complete audio file into memory
  69.     AudioPlayer ap = new AudioPlayer(filename, sampleRate, processing);
  70.     audioThread.addAudioGenerator(ap);
  71.     // now we need to tell the audiothread
  72.     // to ask the audioplayer for samples
  73.     return ap;
  74.   }
  75.  
  76.   /**
  77.    * Create a wavetable player object with a wavetable of the sent
  78.    * size. Small wavetables (<128) make for a 'nastier' sound!
  79.    *
  80.    */
  81.   public WavetableSynth createWavetableSynth(int size) {
  82.     // this will load the complete audio file into memory
  83.     WavetableSynth ap = new WavetableSynth(size, sampleRate);
  84.     audioThread.addAudioGenerator(ap);
  85.     // now we need to tell the audiothread
  86.     // to ask the audioplayer for samples
  87.     return ap;
  88.   }
  89.   // /**
  90.   //  * Create an AudioStreamPlayer which can stream audio from the
  91.   //  * internet as well as local files.  Does not provide precise
  92.   //  * control over looping and playhead like AudioPlayer does.  Use this for
  93.   //  * longer audio files and audio from the internet.
  94.   //  */
  95.   // public AudioStreamPlayer createAudioStreamPlayer(String url) {
  96.   //     AudioStreamPlayer asp = new AudioStreamPlayer(url);
  97.   //     return asp;
  98.   // }
  99. }
  100.  
  101.  
  102.  
  103.  
  104. /**
  105.  * This class can play audio files and includes an fx chain
  106.  */
  107. public class AudioPlayer implements Synth, AudioGenerator {
  108.   private FXChain fxChain;
  109.   private boolean isPlaying;
  110.   private boolean isLooping;
  111.   private boolean analysing;
  112.   private FFT fft;
  113.   private int fftInd;
  114.   private float[] fftFrame;
  115.   private float[] powerSpectrum;
  116.  
  117.   //private float startTimeSecs;
  118.   //private float speed;
  119.   private int length;
  120.   private short[] audioData;
  121.   private float startPos;
  122.   private float readHead;
  123.   private float dReadHead;
  124.   private float sampleRate;
  125.   private float masterVolume;
  126.  
  127.   float x1, x2, y1, y2, x3, y3;
  128.  
  129.   public AudioPlayer(float sampleRate) {
  130.     fxChain = new FXChain(sampleRate);
  131.     this.sampleRate = sampleRate;
  132.   }
  133.  
  134.   public AudioPlayer (String filename, float sampleRate, PApplet processing) {
  135.     //super(filename);
  136.     this(sampleRate);
  137.     try {
  138.       // how long is the file in bytes?
  139.       //long byteCount = getAssets().openFd(filename).getLength();
  140.       File f = new File(processing.dataPath(filename));
  141.       long byteCount = f.length();
  142.       //System.out.println("bytes in "+filename+" "+byteCount);
  143.  
  144.       // check the format of the audio file first!
  145.       // only accept mono 16 bit wavs
  146.       //InputStream is = getAssets().open(filename);
  147.       BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
  148.  
  149.       // chop!!
  150.  
  151.       int bitDepth;
  152.       int channels;
  153.       boolean isPCM;
  154.       // allows us to read up to 4 bytes at a time
  155.       byte[] byteBuff = new byte[4];
  156.  
  157.       // skip 20 bytes to get file format
  158.       // (1 byte)
  159.       bis.skip(20);
  160.       bis.read(byteBuff, 0, 2); // read 2 so we are at 22 now
  161.       isPCM = ((short)byteBuff[0]) == 1 ? true:false;
  162.       //System.out.println("File isPCM "+isPCM);
  163.  
  164.       // skip 22 bytes to get # channels
  165.       // (1 byte)
  166.       bis.read(byteBuff, 0, 2);// read 2 so we are at 24 now
  167.       channels = (short)byteBuff[0];
  168.       //System.out.println("#channels "+channels+" "+byteBuff[0]);
  169.       // skip 24 bytes to get sampleRate
  170.       // (32 bit int)
  171.       bis.read(byteBuff, 0, 4); // read 4 so now we are at 28
  172.       sampleRate = bytesToInt(byteBuff, 4);
  173.       //System.out.println("Sample rate "+sampleRate);
  174.       // skip 34 bytes to get bits per sample
  175.       // (1 byte)
  176.       bis.skip(6); // we were at 28...
  177.       bis.read(byteBuff, 0, 2);// read 2 so we are at 36 now
  178.       bitDepth = (short)byteBuff[0];
  179.       //System.out.println("bit depth "+bitDepth);
  180.       // convert to word count...
  181.       bitDepth /= 8;
  182.       // now start processing the raw data
  183.       // data starts at byte 36
  184.       int sampleCount = (int) ((byteCount - 36) / (bitDepth * channels));
  185.       audioData = new short[sampleCount];
  186.       int skip = (channels -1) * bitDepth;
  187.       int sample = 0;
  188.       // skip a few sample as it sounds like shit
  189.       bis.skip(bitDepth * 4);
  190.       while (bis.available () >= (bitDepth+skip)) {
  191.         bis.read(byteBuff, 0, bitDepth);// read 2 so we are at 36 now
  192.         //int val = bytesToInt(byteBuff, bitDepth);
  193.         // resample to 16 bit by casting to a short
  194.         audioData[sample] = (short) bytesToInt(byteBuff, bitDepth);
  195.         bis.skip(skip);
  196.         sample ++;
  197.       }
  198.  
  199.       float secs = (float)sample / (float)sampleRate;
  200.       //System.out.println("Read "+sample+" samples expected "+sampleCount+" time "+secs+" secs ");      
  201.       bis.close();
  202.  
  203.  
  204.       // unchop
  205.       readHead = 0;
  206.       startPos = 0;
  207.       // default to 1 sample shift per tick
  208.       dReadHead = 1;
  209.       isPlaying = false;
  210.       isLooping = true;
  211.       masterVolume = 1;
  212.     }
  213.     catch (FileNotFoundException e) {
  214.  
  215.       e.printStackTrace();
  216.     }
  217.     catch (IOException e) {
  218.       e.printStackTrace();
  219.     }
  220.   }
  221.  
  222.   public void setAnalysing(boolean analysing_) {
  223.     this.analysing = analysing_;
  224.     if (analysing) {// initialise the fft
  225.       fft = new FFT();
  226.       fftInd = 0;
  227.       fftFrame = new float[1024];
  228.       powerSpectrum = new float[fftFrame.length/2];
  229.     }
  230.   }
  231.  
  232.   public float getAveragePower() {
  233.     if (analysing) {
  234.       // calc the average
  235.       float sum = 0;
  236.       for (int i=0;i<powerSpectrum.length;i++) {
  237.         sum += powerSpectrum[i];
  238.       }
  239.       sum /= powerSpectrum.length;
  240.       return sum;
  241.     }
  242.     else {
  243.       System.out.println("call setAnalysing to enable power analysis");
  244.       return 0;
  245.     }
  246.   }
  247.   public float[] getPowerSpectrum() {
  248.     if (analysing) {
  249.       return powerSpectrum;
  250.     }
  251.     else {
  252.       System.out.println("call setAnalysing to enable power analysis");
  253.       return null;
  254.     }
  255.   }
  256.  
  257.   /**
  258.    *convert the sent byte array into an int. Assumes little endian byte ordering.
  259.    *@param bytes - the byte array containing the data
  260.    *@param wordSizeBytes - the number of bytes to read from bytes array
  261.    *@return int - the byte array as an int
  262.    */
  263.   private int bytesToInt(byte[] bytes, int wordSizeBytes) {
  264.     int val = 0;
  265.     for (int i=wordSizeBytes-1; i>=0; i--) {
  266.       val <<= 8;
  267.       val |= (int)bytes[i] & 0xFF;
  268.     }
  269.     return val;
  270.   }
  271.  
  272.   /**
  273.    * Test if this audioplayer is playing right now
  274.    * @return true if it is playing, false otherwise
  275.    */
  276.   public boolean isPlaying() {
  277.     return isPlaying;
  278.   }
  279.  
  280.   /**
  281.    * Set the loop mode for this audio player
  282.    * @param looping
  283.    */
  284.   public void setLooping(boolean looping) {
  285.     isLooping = looping;
  286.   }
  287.  
  288.   /**
  289.    * Move the start pointer of the audio player to the sent time in ms
  290.    * @param timeMs - the time in ms
  291.    */
  292.   public void cue(int timeMs) {
  293.     //startPos = ((timeMs / 1000) * sampleRate) % audioData.length;
  294.     //readHead = startPos;
  295.     //System.out.println("AudioPlayer Cueing to "+timeMs);
  296.     if (timeMs >= 0) {// ignore crazy values
  297.       readHead = (((float)timeMs / 1000f) * sampleRate) % audioData.length;
  298.       //System.out.println("Read head went to "+readHead);
  299.     }
  300.   }
  301.  
  302.   /**
  303.    *  Set the playback speed,
  304.    * @param speed - playback speed where 1 is normal speed, 2 is double speed
  305.    */
  306.   public void speed(float speed) {
  307.     //System.out.println("setting speed to "+speed);
  308.     dReadHead = speed;
  309.   }
  310.  
  311.   /**
  312.    * Set the master volume of the AudioPlayer
  313.    */
  314.  
  315.   public void volume(float volume) {
  316.     masterVolume = volume;
  317.   }
  318.  
  319.   /**
  320.    * Get the length of the audio file in samples
  321.    * @return int - the  length of the audio file in samples
  322.    */
  323.   public int getLength() {
  324.     return audioData.length;
  325.   }
  326.   /**
  327.    * Get the length of the sound in ms, suitable for sending to 'cue'
  328.    */
  329.   public float getLengthMs() {
  330.     return ((float) audioData.length / sampleRate * 1000f);
  331.   }
  332.  
  333.   /**
  334.    * Start playing the sound.
  335.    */
  336.   public void play() {
  337.     isPlaying = true;
  338.   }
  339.  
  340.   /**
  341.    * Stop playing the sound
  342.    */
  343.   public void stop() {
  344.     isPlaying = false;
  345.   }
  346.  
  347.   /**
  348.    * implementation of the AudioGenerator interface
  349.    */
  350.   public short getSample() {
  351.     if (!isPlaying) {
  352.       return 0;
  353.     }
  354.     else {
  355.       short sample;
  356.       readHead += dReadHead;
  357.       if (readHead > (audioData.length - 1)) {// got to the end
  358.         //% (float)audioData.length;
  359.         if (isLooping) {// back to the start for loop mode
  360.           readHead = readHead % (float)audioData.length;
  361.         }
  362.         else {
  363.           readHead = 0;
  364.           isPlaying = false;
  365.         }
  366.       }
  367.  
  368.       // linear interpolation here
  369.       // declaring these at the top...
  370.       // easy to understand version...
  371.       //      float x1, x2, y1, y2, x3, y3;
  372.       x1 = floor(readHead);
  373.       x2 = x1 + 1;
  374.       y1 = audioData[(int)x1];
  375.       y2 = audioData[(int) (x2 % audioData.length)];
  376.       x3 = readHead;
  377.       // calc
  378.       y3 =  y1 + ((x3 - x1) * (y2 - y1));
  379.       y3 *= masterVolume;
  380.       sample = fxChain.getSample((short) y3);
  381.       if (analysing) {
  382.         // accumulate samples for the fft
  383.         fftFrame[fftInd] = (float)sample / 32768f;
  384.         fftInd ++;
  385.         if (fftInd == fftFrame.length - 1) {// got a frame
  386.           powerSpectrum = fft.process(fftFrame, true);
  387.           fftInd = 0;
  388.         }
  389.       }
  390.  
  391.       //return sample;
  392.       return (short)y3;
  393.     }
  394.   }
  395.  
  396.   public void setAudioData(short[] audioData) {
  397.     this.audioData = audioData;
  398.   }
  399.  
  400.   public short[] getAudioData() {
  401.     return audioData;
  402.   }
  403.  
  404.   public void setDReadHead(float dReadHead) {
  405.     this.dReadHead = dReadHead;
  406.   }
  407.  
  408.   ///
  409.   //the synth interface
  410.   //
  411.  
  412.   public void ramp(float val, float timeMs) {
  413.     fxChain.ramp(val, timeMs);
  414.   }
  415.  
  416.  
  417.  
  418.   public void setDelayTime(float delayMs) {
  419.     fxChain.setDelayTime( delayMs);
  420.   }
  421.  
  422.   public void setDelayFeedback(float fb) {
  423.     fxChain.setDelayFeedback(fb);
  424.   }
  425.  
  426.   public void setFilter(float cutoff, float resonance) {
  427.     fxChain.setFilter( cutoff, resonance);
  428.   }
  429. }
  430.  
  431. /**
  432.  * This class can play wavetables and includes an fx chain
  433.  */
  434. public class WavetableSynth extends AudioPlayer {
  435.  
  436.   private short[] sine;
  437.   private short[] saw;
  438.   private short[] wavetable;
  439.   private float sampleRate;
  440.  
  441.   public WavetableSynth(int size, float sampleRate) {
  442.     super(sampleRate);
  443.     sine = new short[size];
  444.     for (float i = 0; i < sine.length; i++) {
  445.       float phase;
  446.       phase = TWO_PI / size * i;
  447.       sine[(int)i] = (short) (sin(phase) * 32768);
  448.     }
  449.     saw = new short[size];
  450.     for (float i = 0; i<saw.length; i++) {
  451.       saw[(int)i] = (short) (i / (float)saw.length *32768);
  452.     }
  453.  
  454.     this.sampleRate = sampleRate;
  455.     setAudioData(sine);
  456.     setLooping(true);
  457.   }
  458.  
  459.   public void setFrequency(float freq) {
  460.     if (freq > 0) {
  461.       //System.out.println("freq freq "+freq);
  462.       setDReadHead((float)getAudioData().length / sampleRate * freq);
  463.     }
  464.   }
  465.  
  466.   public void loadWaveForm(float[] wavetable_) {
  467.     if (wavetable == null || wavetable_.length != wavetable.length) {
  468.       // only reallocate if there is a change in length
  469.       wavetable = new short[wavetable_.length];
  470.     }
  471.     for (int i=0;i<wavetable.length;i++) {
  472.       wavetable[i] = (short) (wavetable_[i] * 32768);
  473.     }
  474.     setAudioData(wavetable);
  475.   }
  476. }
  477.  
  478. public interface Synth {
  479.   public void volume(float volume);
  480.   public void ramp(float val, float timeMs);  
  481.   public void setDelayTime(float delayMs);  
  482.   public void setDelayFeedback(float fb);  
  483.   public void setFilter(float cutoff, float resonance);
  484.   public void setAnalysing(boolean analysing);
  485.   public float getAveragePower();
  486.   public float[] getPowerSpectrum();
  487. }
  488.  
  489. public class AudioThread extends Thread
  490. {
  491.   private int minSize;
  492.   //private AudioTrack track;
  493.   private short[] bufferS;
  494.   private byte[] bOutput;
  495.   private ArrayList audioGens;
  496.   private boolean running;
  497.  
  498.   private FFT fft;
  499.   private float[] fftFrame;
  500.   private SourceDataLine sourceDataLine;
  501.   private int blockSize;
  502.  
  503.   public AudioThread(float samplingRate, int blockSize) {
  504.     this(samplingRate, blockSize, false);
  505.   }
  506.  
  507.   public AudioThread(float samplingRate, int blockSize, boolean enableFFT)
  508.   {
  509.     this.blockSize = blockSize;
  510.     audioGens = new ArrayList();
  511.     // we'll do our dsp in shorts
  512.     bufferS = new short[blockSize];
  513.     // but we'll convert to bytes when sending to the sound card
  514.     bOutput = new byte[blockSize * 2];
  515.     AudioFormat audioFormat = new AudioFormat(samplingRate, 16, 1, true, false);
  516.     DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
  517.  
  518.     sourceDataLine = null;
  519.     // here we try to initialise the audio system. try catch is exception handling, i.e.
  520.     // dealing with things not working as expected
  521.     try {
  522.       sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
  523.       sourceDataLine.open(audioFormat, bOutput.length);
  524.       sourceDataLine.start();
  525.       running = true;
  526.     }
  527.     catch (LineUnavailableException lue) {
  528.       // it went wrong!
  529.       lue.printStackTrace(System.err);
  530.       System.out.println("Could not initialise audio. check above stack trace for more info");
  531.       //System.exit(1);
  532.     }
  533.  
  534.  
  535.     if (enableFFT) {
  536.       try {
  537.         fft = new FFT();
  538.       }
  539.       catch(Exception e) {
  540.         System.out.println("Error setting up the audio analyzer");
  541.         e.printStackTrace();
  542.       }
  543.     }
  544.   }
  545.  
  546.   // overidden from Thread
  547.   public void run() {
  548.     running = true;
  549.     while (running) {
  550.       //System.out.println("AudioThread : ags  "+audioGens.size());
  551.       for (int i=0;i<bufferS.length;i++) {
  552.         // we add up using a 32bit int
  553.         // to prevent clipping
  554.         int val = 0;
  555.         if (audioGens.size() > 0) {
  556.           for (int j=0;j<audioGens.size(); j++) {
  557.             AudioGenerator ag = (AudioGenerator)audioGens.get(j);
  558.             val += ag.getSample();
  559.           }
  560.           val /= audioGens.size();
  561.         }
  562.         bufferS[i] = (short) val;
  563.       }
  564.       // send it to the audio device!
  565.       sourceDataLine.write(shortsToBytes(bufferS, bOutput), 0, bOutput.length);
  566.     }
  567.   }
  568.  
  569.   public void addAudioGenerator(AudioGenerator ag) {
  570.     audioGens.add(ag);
  571.   }
  572.  
  573.   /**
  574.    * converts an array of 16 bit samples to bytes
  575.    * in little-endian (low-byte, high-byte) format.
  576.    */
  577.   private byte[] shortsToBytes(short[] sData, byte[] bData) {
  578.     int index = 0;
  579.     short sval;
  580.     for (int i = 0; i < sData.length; i++) {
  581.       //short sval = (short) (fData[j][i] * ShortMaxValueAsFloat);
  582.       sval = sData[i];
  583.       bData[index++] = (byte) (sval & 0x00FF);
  584.       bData[index++] = (byte) ((sval & 0xFF00) >> 8);
  585.     }
  586.     return bData;
  587.   }
  588.  
  589.   /**
  590.    * Returns a recent snapshot of the power spectrum
  591.    */
  592.   public float[] getPowerSpectrum() {
  593.     // process the last buffer that was calculated
  594.     if (fftFrame == null) {
  595.       fftFrame = new float[bufferS.length];
  596.     }
  597.     for (int i=0;i<fftFrame.length;i++) {
  598.       fftFrame[i] = ((float) bufferS[i] / 32768f);
  599.     }
  600.     return fft.process(fftFrame, true);
  601.     //return powerSpectrum;
  602.   }
  603. }
  604.  
  605. /**
  606.  * Implement this interface so the AudioThread can request samples from you
  607.  */
  608. public interface AudioGenerator {
  609.   /** AudioThread calls this when it wants a sample */
  610.   short getSample();
  611. }
  612.  
  613.  
  614. public class FXChain {
  615.   private float currentAmp;
  616.   private float dAmp;
  617.   private float targetAmp;
  618.   private boolean goingUp;
  619.   private Filter filter;
  620.  
  621.   private float[] dLine;  
  622.  
  623.   private float sampleRate;
  624.  
  625.   public FXChain(float sampleRate_) {
  626.     sampleRate = sampleRate_;
  627.     currentAmp = 1;
  628.     dAmp = 0;
  629.     // filter = new MickFilter(sampleRate);
  630.     filter = new RLPF(sampleRate);
  631.  
  632.     //filter.setFilter(0.1, 0.1);
  633.   }
  634.  
  635.   public void ramp(float val, float timeMs) {
  636.     // calc the dAmp;
  637.     // - change per ms
  638.     targetAmp = val;
  639.     dAmp = (targetAmp - currentAmp) / (timeMs / 1000 * sampleRate);
  640.     if (targetAmp > currentAmp) {
  641.       goingUp = true;
  642.     }
  643.     else {
  644.       goingUp = false;
  645.     }
  646.   }
  647.  
  648.  
  649.   public void setDelayTime(float delayMs) {
  650.   }
  651.  
  652.   public void setDelayFeedback(float fb) {
  653.   }
  654.  
  655.   public void volume(float volume) {
  656.   }
  657.  
  658.  
  659.   public short getSample(short input) {
  660.     float in;
  661.     in = (float) input / 32768;// -1 to 1
  662.  
  663.     in =  filter.applyFilter(in);
  664.     if (goingUp && currentAmp < targetAmp) {
  665.       currentAmp += dAmp;
  666.     }
  667.     else if (!goingUp && currentAmp > targetAmp) {
  668.       currentAmp += dAmp;
  669.     }  
  670.  
  671.     if (currentAmp > 1) {
  672.       currentAmp = 1;
  673.     }
  674.     if (currentAmp < 0) {
  675.       currentAmp = 0;
  676.     }  
  677.     in *= currentAmp;  
  678.     return (short) (in * 32768);
  679.   }
  680.  
  681.   public void setFilter(float f, float r) {
  682.     filter.setFilter(f, r);
  683.   }
  684. }
  685.  
  686.  
  687. // /**
  688. //  * Represents an audio source is streamed as opposed to being completely loaded (as WavSource is)
  689. //  */
  690. // public class AudioStreamPlayer {
  691. //   /** a class from the android API*/
  692. //   private MediaPlayer mediaPlayer;
  693. //   /** a class from the android API*/
  694. //   private Visualizer viz;
  695. //   private byte[] waveformBuffer;
  696. //   private byte[] fftBuffer;
  697. //   private byte[] powerSpectrum;
  698.  
  699. //   /**
  700. //    * create a stream source from the sent url
  701. //    */
  702. //   public AudioStreamPlayer(String url) {
  703. //       try {
  704. //     mediaPlayer = new MediaPlayer();
  705. //     //mp.setAuxEffectSendLevel(1);
  706. //     mediaPlayer.setLooping(true);
  707.  
  708. //     // try to parse the URL... if that fails, we assume it
  709. //     // is a local file in the assets folder
  710. //     try {
  711. //         URL uRL = new URL(url);
  712. //         mediaPlayer.setDataSource(url);
  713. //     }
  714. //     catch (MalformedURLException eek) {
  715. //         // couldn't parse the url, assume its a local file
  716. //         AssetFileDescriptor afd = getAssets().openFd(url);
  717. //         //mp.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
  718. //         mediaPlayer.setDataSource(afd.getFileDescriptor());
  719. //         afd.close();
  720. //     }
  721.  
  722. //     mediaPlayer.prepare();
  723. //     //mediaPlayer.start();
  724. //     //System.out.println("Created audio with id "+mediaPlayer.getAudioSessionId());
  725. //     viz = new Visualizer(mediaPlayer.getAudioSessionId());
  726. //     viz.setEnabled(true);
  727. //     waveformBuffer = new byte[viz.getCaptureSize()];
  728. //     fftBuffer = new byte[viz.getCaptureSize()/2];
  729. //     powerSpectrum = new byte[viz.getCaptureSize()/2];
  730. //       }
  731. //       catch (Exception e) {
  732. //     System.out.println("StreamSource could not be initialised. Check url... "+url+ " and that you have added the permission INTERNET, RECORD_AUDIO and MODIFY_AUDIO_SETTINGS to the manifest,");
  733. //     e.printStackTrace();
  734. //       }
  735. //   }
  736.  
  737. //   public void play() {
  738. //       mediaPlayer.start();
  739. //   }
  740.  
  741. //   public int getLengthMs() {
  742. //       return mediaPlayer.getDuration();
  743. //   }
  744.  
  745. //   public void cue(float timeMs) {
  746. //       if (timeMs >= 0 && timeMs < getLengthMs()) {// ignore crazy values
  747. //     mediaPlayer.seekTo((int)timeMs);
  748. //       }
  749. //   }
  750.  
  751. //   /**
  752. //    * Returns a recent snapshot of the power spectrum as 8 bit values
  753. //    */
  754. //   public byte[] getPowerSpectrum() {
  755. //       // calculate the spectrum
  756. //       viz.getFft(fftBuffer);
  757. //       short real, imag;
  758. //       for (int i=2;i<fftBuffer.length;i+=2) {
  759. //     real = (short) fftBuffer[i];
  760. //     imag = (short) fftBuffer[i+1];
  761. //     powerSpectrum[i/2] = (byte) ((real * real)  + (imag * imag));
  762. //       }
  763. //       return powerSpectrum;
  764. //   }
  765.  
  766. //   /**
  767. //    * Returns a recent snapshot of the waveform being played
  768. //    */
  769. //   public byte[] getWaveForm() {
  770. //       // retrieve the waveform
  771. //       viz.getWaveForm(waveformBuffer);
  772. //       return waveformBuffer;
  773. //   }
  774. // }
  775.  
  776. /**
  777.  * Use this class to retrieve data about the movement of the device
  778.  */
  779. public class Accelerometer {
  780.   //private SensorManager sensorManager;
  781.   //private Sensor accelerometer;
  782.   private float[] values;
  783.  
  784.   public Accelerometer() {
  785.     //sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
  786.     //accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  787.     //sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
  788.     values = new float[3];
  789.     System.out.println("Java accelerometer will generate values of zero!");
  790.   }
  791.  
  792.   public float[] getValues() {
  793.     return values;
  794.   }
  795.  
  796.   public float getX() {
  797.     return values[0];
  798.   }
  799.  
  800.   public float getY() {
  801.     return values[1];
  802.   }
  803.  
  804.   public float getZ() {
  805.     return values[2];
  806.   }
  807. }
  808.  
  809. public interface Filter {
  810.   public void setFilter(float f, float r);
  811.   public float applyFilter(float in);
  812. }
  813.  
  814. /** https://github.com/supercollider/supercollider/blob/master/server/plugins/FilterUGens.cpp */
  815.  
  816. public class RLPF implements Filter {
  817.   float a0, b1, b2, y1, y2;
  818.   float freq;
  819.   float reson;
  820.   float sampleRate;
  821.   boolean changed;
  822.  
  823.   public RLPF(float sampleRate_) {
  824.     this.sampleRate = sampleRate_;
  825.     reset();
  826.     this.setFilter(sampleRate / 4, 0.01f);
  827.   }
  828.   private void reset() {
  829.     a0 = 0.f;
  830.     b1 = 0.f;
  831.     b2 = 0.f;
  832.     y1 = 0.f;
  833.     y2 = 0.f;
  834.   }
  835.   /** f is in the range 0-sampleRate/2 */
  836.   public void setFilter(float f, float r) {
  837.     // constrain
  838.     // limit to 0-1
  839.     f = constrain(f, 0, sampleRate/4);
  840.     r = constrain(r, 0, 1);
  841.     // invert so high r -> high resonance!
  842.     r = 1-r;
  843.     // remap to appropriate ranges
  844.     f = map(f, 0f, sampleRate/4, 30f, sampleRate / 4);
  845.     r = map(r, 0f, 1f, 0.005f, 2f);
  846.  
  847.     System.out.println("rlpf: f "+f+" r "+r);
  848.  
  849.     this.freq = f * TWO_PI / sampleRate;
  850.     this.reson = r;
  851.     changed = true;
  852.   }
  853.  
  854.   public float applyFilter(float in) {
  855.     float y0;
  856.     if (changed) {
  857.       float D = tan(freq * reson * 0.5f);
  858.       float C = ((1.f-D)/(1.f+D));
  859.       float cosf = cos(freq);
  860.       b1 = (1.f + C) * cosf;
  861.       b2 = -C;
  862.       a0 = (1.f + C - b1) * .25f;
  863.       changed = false;
  864.     }
  865.     y0 = a0 * in + b1 * y1 + b2 * y2;
  866.     y2 = y1;
  867.     y1 = y0;
  868.     if (Float.isNaN(y0)) {
  869.       reset();
  870.     }
  871.     return y0;
  872.   }
  873. }
  874.  
  875. /** https://github.com/micknoise/Maximilian/blob/master/maximilian.cpp */
  876.  
  877. class MickFilter implements Filter {
  878.  
  879.   private float f, res;
  880.   private float cutoff, z, c, x, y, out;
  881.   private float sampleRate;
  882.  
  883.   MickFilter(float sampleRate) {
  884.     this.sampleRate = sampleRate;
  885.   }
  886.  
  887.   public void setFilter(float f, float r) {
  888.     f = constrain(f, 0, 1);
  889.     res = constrain(r, 0, 1);
  890.     f = map(f, 0, 1, 25, sampleRate / 4);
  891.     r = map(r, 0, 1, 1, 25);
  892.     this.f = f;
  893.     this.res = r;    
  894.  
  895.     //System.out.println("mickF: f "+f+" r "+r);
  896.   }
  897.   public float applyFilter(float in) {
  898.     return lores(in, f, res);
  899.   }
  900.  
  901.   public float lores(float input, float cutoff1, float resonance) {
  902.     //cutoff=cutoff1*0.5;
  903.     //if (cutoff<10) cutoff=10;
  904.     //if (cutoff>(sampleRate*0.5)) cutoff=(sampleRate*0.5);
  905.     //if (resonance<1.) resonance = 1.;
  906.  
  907.     //if (resonance>2.4) resonance = 2.4;
  908.     z=cos(TWO_PI*cutoff/sampleRate);
  909.     c=2-2*z;
  910.     float r=(sqrt(2.0f)*sqrt(-pow((z-1.0f), 3.0f))+resonance*(z-1))/(resonance*(z-1));
  911.     x=x+(input-y)*c;
  912.     y=y+x;
  913.     x=x*r;
  914.     out=y;
  915.     return out;
  916.   }
  917. }
  918.  
  919.  
  920. /*
  921.  * This file is part of Beads. See http://www.beadsproject.net for all information.
  922.  * CREDIT: This class uses portions of code taken from MPEG7AudioEnc. See readme/CREDITS.txt.
  923.  */
  924.  
  925. /**
  926.  * FFT performs a Fast Fourier Transform and forwards the complex data to any listeners.
  927.  * The complex data is a float of the form float[2][frameSize], with real and imaginary
  928.  * parts stored respectively.
  929.  *
  930.  * @beads.category analysis
  931.  */
  932. public class FFT {
  933.  
  934.   /** The real part. */
  935.   protected float[] fftReal;
  936.  
  937.   /** The imaginary part. */
  938.   protected float[] fftImag;
  939.  
  940.   private float[] dataCopy = null;
  941.   private float[][] features;
  942.   private float[] powers;
  943.   private int numFeatures;
  944.  
  945.   /**
  946.    * Instantiates a new FFT.
  947.    */
  948.   public FFT() {
  949.     features = new float[2][];
  950.   }
  951.  
  952.   /* (non-Javadoc)
  953.    * @see com.olliebown.beads.core.UGen#calculateBuffer()
  954.    */
  955.   public float[] process(float[] data, boolean direction) {
  956.     if (powers == null) powers = new float[data.length/2];
  957.     if (dataCopy==null || dataCopy.length!=data.length)
  958.       dataCopy = new float[data.length];
  959.     System.arraycopy(data, 0, dataCopy, 0, data.length);
  960.  
  961.     fft(dataCopy, dataCopy.length, direction);
  962.     numFeatures = dataCopy.length;
  963.     fftReal = calculateReal(dataCopy, dataCopy.length);
  964.     fftImag = calculateImaginary(dataCopy, dataCopy.length);
  965.     features[0] = fftReal;
  966.     features[1] = fftImag;
  967.     // now calc the powers
  968.     return specToPowers(fftReal, fftImag, powers);
  969.   }
  970.  
  971.   public float[] specToPowers(float[] real, float[] imag, float[] powers) {
  972.     float re, im;
  973.     double pow;
  974.     for (int i=0;i<powers.length;i++) {
  975.       //real = spectrum[i][j].re();
  976.       //imag = spectrum[i][j].im();
  977.       re = real[i];
  978.       im = imag[i];
  979.       powers[i] = (re*re + im * im);
  980.       powers[i] = (float) Math.sqrt(powers[i]) / 10;
  981.       // convert to dB
  982.       pow = (double) powers[i];
  983.       powers[i] = (float)(10 *  Math.log10(pow * pow)); // (-100 - 100)
  984.       powers[i] = (powers[i] + 100) * 0.005f; // 0-1
  985.     }
  986.     return powers;
  987.   }
  988.  
  989.   /**
  990.    * The frequency corresponding to a specific bin
  991.    *
  992.    * @param samplingFrequency The Sampling Frequency of the AudioContext
  993.    * @param blockSize The size of the block analysed
  994.    * @param binNumber
  995.    */
  996.   public  float binFrequency(float samplingFrequency, int blockSize, float binNumber)
  997.   {    
  998.     return binNumber*samplingFrequency/blockSize;
  999.   }
  1000.  
  1001.   /**
  1002.    * Returns the average bin number corresponding to a particular frequency.
  1003.    * Note: This function returns a float. Take the Math.round() of the returned value to get an integral bin number.
  1004.    *
  1005.    * @param samplingFrequency The Sampling Frequency of the AudioContext
  1006.    * @param blockSize The size of the fft block
  1007.    * @param freq  The frequency
  1008.    */
  1009.  
  1010.   public  float binNumber(float samplingFrequency, int blockSize, float freq)
  1011.   {
  1012.     return blockSize*freq/samplingFrequency;
  1013.   }
  1014.  
  1015.   /** The nyquist frequency for this samplingFrequency
  1016.    *
  1017.    * @params samplingFrequency the sample
  1018.    */
  1019.   public  float nyquist(float samplingFrequency)
  1020.   {
  1021.     return samplingFrequency/2;
  1022.   }
  1023.  
  1024.   /*
  1025.      * All of the code below this line is taken from Holger Crysandt's MPEG7AudioEnc project.
  1026.    * See http://mpeg7audioenc.sourceforge.net/copyright.html for license and copyright.
  1027.    */
  1028.  
  1029.   /**
  1030.    * Gets the real part from the complex spectrum.
  1031.    *
  1032.    * @param spectrum
  1033.    *            complex spectrum.
  1034.    * @param length
  1035.    *       length of data to use.
  1036.    *
  1037.    * @return real part of given length of complex spectrum.
  1038.    */
  1039.   protected  float[] calculateReal(float[] spectrum, int length) {
  1040.     float[] real = new float[length];
  1041.     real[0] = spectrum[0];
  1042.     real[real.length/2] = spectrum[1];
  1043.     for (int i=1, j=real.length-1; i<j; ++i, --j)
  1044.       real[j] = real[i] = spectrum[2*i];
  1045.     return real;
  1046.   }
  1047.  
  1048.   /**
  1049.    * Gets the imaginary part from the complex spectrum.
  1050.    *
  1051.    * @param spectrum
  1052.    *            complex spectrum.
  1053.    * @param length
  1054.    *       length of data to use.
  1055.    *
  1056.    * @return imaginary part of given length of complex spectrum.
  1057.    */
  1058.   protected  float[] calculateImaginary(float[] spectrum, int length) {
  1059.     float[] imag = new float[length];
  1060.     for (int i=1, j=imag.length-1; i<j; ++i, --j)
  1061.       imag[i] = -(imag[j] = spectrum[2*i+1]);
  1062.     return imag;
  1063.   }
  1064.  
  1065.   /**
  1066.    * Perform FFT on data with given length, regular or inverse.
  1067.    *
  1068.    * @param data the data
  1069.    * @param n the length
  1070.    * @param isign true for regular, false for inverse.
  1071.    */
  1072.   protected  void fft(float[] data, int n, boolean isign) {
  1073.     float c1 = 0.5f;
  1074.     float c2, h1r, h1i, h2r, h2i;
  1075.     double wr, wi, wpr, wpi, wtemp;
  1076.     double theta = 3.141592653589793/(n>>1);
  1077.     if (isign) {
  1078.       c2 = -.5f;
  1079.       four1(data, n>>1, true);
  1080.     }
  1081.     else {
  1082.       c2 = .5f;
  1083.       theta = -theta;
  1084.     }
  1085.     wtemp = Math.sin(.5*theta);
  1086.     wpr = -2.*wtemp*wtemp;
  1087.     wpi = Math.sin(theta);
  1088.     wr = 1. + wpr;
  1089.     wi = wpi;
  1090.     int np3 = n + 3;
  1091.     for (int i=2,imax = n >> 2, i1, i2, i3, i4; i <= imax; ++i) {
  1092.       /** @TODO this can be optimized */
  1093.       i4 = 1 + (i3 = np3 - (i2 = 1 + (i1 = i + i - 1)));
  1094.       --i4;
  1095.       --i2;
  1096.       --i3;
  1097.       --i1;
  1098.       h1i =  c1*(data[i2] - data[i4]);
  1099.       h2r = -c2*(data[i2] + data[i4]);
  1100.       h1r =  c1*(data[i1] + data[i3]);
  1101.       h2i =  c2*(data[i1] - data[i3]);
  1102.       data[i1] = (float) ( h1r + wr*h2r - wi*h2i);
  1103.       data[i2] = (float) ( h1i + wr*h2i + wi*h2r);
  1104.       data[i3] = (float) ( h1r - wr*h2r + wi*h2i);
  1105.       data[i4] = (float) (-h1i + wr*h2i + wi*h2r);
  1106.       wr = (wtemp=wr)*wpr - wi*wpi + wr;
  1107.       wi = wi*wpr + wtemp*wpi + wi;
  1108.     }
  1109.     if (isign) {
  1110.       float tmp = data[0];
  1111.       data[0] += data[1];
  1112.       data[1] = tmp - data[1];
  1113.     }
  1114.     else {
  1115.       float tmp = data[0];
  1116.       data[0] = c1 * (tmp + data[1]);
  1117.       data[1] = c1 * (tmp - data[1]);
  1118.       four1(data, n>>1, false);
  1119.     }
  1120.   }
  1121.  
  1122.   /**
  1123.    * four1 algorithm.
  1124.    *
  1125.    * @param data
  1126.    *            the data.
  1127.    * @param nn
  1128.    *            the nn.
  1129.    * @param isign
  1130.    *            regular or inverse.
  1131.    */
  1132.   private  void four1(float data[], int nn, boolean isign) {
  1133.     int n, mmax, istep;
  1134.     double wtemp, wr, wpr, wpi, wi, theta;
  1135.     float tempr, tempi;
  1136.  
  1137.     n = nn << 1;        
  1138.     for (int i = 1, j = 1; i < n; i += 2) {
  1139.       if (j > i) {
  1140.         // SWAP(data[j], data[i]);
  1141.         float swap = data[j-1];
  1142.         data[j-1] = data[i-1];
  1143.         data[i-1] = swap;
  1144.         // SWAP(data[j+1], data[i+1]);
  1145.         swap = data[j];
  1146.         data[j] = data[i];
  1147.         data[i] = swap;
  1148.       }      
  1149.       int m = n >> 1;
  1150.       while (m >= 2 && j > m) {
  1151.         j -= m;
  1152.         m >>= 1;
  1153.       }
  1154.       j += m;
  1155.     }
  1156.     mmax = 2;
  1157.     while (n > mmax) {
  1158.       istep = mmax << 1;
  1159.       theta = 6.28318530717959 / mmax;
  1160.       if (!isign)
  1161.         theta = -theta;
  1162.       wtemp = Math.sin(0.5 * theta);
  1163.       wpr = -2.0 * wtemp * wtemp;
  1164.       wpi = Math.sin(theta);
  1165.       wr = 1.0;
  1166.       wi = 0.0;
  1167.       for (int m = 1; m < mmax; m += 2) {
  1168.         for (int i = m; i <= n; i += istep) {
  1169.           int j = i + mmax;
  1170.           tempr = (float) (wr * data[j-1] - wi * data[j]);  
  1171.           tempi = (float) (wr * data[j]   + wi * data[j-1]);  
  1172.           data[j-1] = data[i-1] - tempr;
  1173.           data[j]   = data[i] - tempi;
  1174.           data[i-1] += tempr;
  1175.           data[i]   += tempi;
  1176.         }
  1177.         wr = (wtemp = wr) * wpr - wi * wpi + wr;
  1178.         wi = wi * wpr + wtemp * wpi + wi;
  1179.       }
  1180.       mmax = istep;
  1181.     }
  1182.   }
  1183. }