Echo effect with minim

PerPer
edited September 2014 in Library Questions

Hi!

Im trying to get an echo effect / delay effect with minim but cant get it to work. I want to finally mix the direct sound from an input and with the delayed (echo effect)

I think i miss something with the .patch. Here are two examples; one with lineInput and one with recorded audio. Both have the same problems:

LiveInput:

import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
AudioInput in; 
Delay myDelay;

void setup() {
  size( 512, 200 );

  minim = new Minim(this);
  out = minim.getLineOut();

  in = minim.getLineIn(Minim.MONO); // input lineIn
  in.setGain(+10); // gain

  // initialize myDelay with continual feedback and audio passthrough
  myDelay = new Delay( 0.4, 0.5, true, true );

  // the LineInput is patched through the delay into the output
  in.patch( myDelay ).patch( out );
}

void draw() {

}

Recorded audio:

import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
AudioPlayer player; 

Delay myDelay;

void setup() {
  size( 512, 200 );

  minim = new Minim(this);
  out = minim.getLineOut();

  player = minim.loadFile("beat.wav"); // load beat
  player.setGain(+5); // gain
  player.play(); // play
  player.loop(); // loop

  // initialize myDelay with continual feedback and audio passthrough
  myDelay = new Delay( 0.4, 0.5, true, true );

  // audio is patched through the delay into the output
  player.patch( myDelay ).patch( out );
}

void draw() {

}

Answers

  • I think you could play the same audio again, just about half a second behind the first one. Do something like this:

    int Starttime=0;
    
        void setup(){
        Starttime=minim();
          if (Starttime + 500 < millis()){
          minim = new Minim(this);
          out = minim.getLineOut();
    
          player = minim.loadFile("beat.wav"); // load beat
          player.setGain(+5); // gain
          player.play(); // play
          player.loop(); // loop
        }
    
    
        }
    
    
        //divide the number after Starttime by 1000 to know how many seconds it is in this case .5
    

    But you will have to add the audio "beat.wav" twice. Then put the first audio in its regular position and leave the second one in the Starttime function. This should make it start 1/2 second later.

    Try it it most likely will work.

    Hope it helps.

  • edited April 2015

    .patch() is a UGen method. AudioInput doesn't extend UGen, so you can't .patch() an AudioInput.

    I think you're supposed to use the LiveInput class, but I haven't got it working yet (sputtery crackly noise).

    I have no idea what's wrong... all it does is read from an AudioStream and pass the values to its output, but it only reads half of the input buffer and mangles the rest.

    I found a 3rd party example that defines a class AudioSocket that implements the AudioListener and AudioSignal interfaces, which allows you to connect an AudioInput to an AudioOutput like so:

       in = minim.getLineIn(Minim.STEREO, buffer_size);
       out = minim.getLineOut(Minim.STEREO, buffer_size);
       socket = new AudioSocket(buffer_size);
    
       in.addListener(socket);
       out.addSignal(socket);
    

    This works great... except its not a UGen, so you still can't patch it.

    So I've hacked together AudioSocket and LiveInput to get a class that extends UGen and implements AudioListener:

    class MyAudioSocket extends UGen implements AudioListener
    {
    
      private float[] left;
      private float[] right;
      private int buffer_max;
      private int inpos, outpos;
      private int count;
    
      MyAudioSocket(int buffer_size)
      {
         int n_buffers = 4;
         buffer_max = n_buffers * buffer_size;
         left = new float[buffer_max];
         right = new float[buffer_max];
         inpos = 0;
         outpos = 0;
         count = 0;
      }
    
      // The AudioListener:samples method accepts new input samples
      synchronized void samples(float[] samp)
      {
        // handle mono by writing samples to both left and right
        samples(samp, samp);
      }
    
      synchronized void samples(float[] sampL, float[] sampR)
      {
        System.arraycopy(sampL, 0, left, inpos, sampL.length);
        System.arraycopy(sampR, 0, right, inpos, sampR.length);
        inpos += sampL.length;
        if (inpos == buffer_max) {
          inpos = 0;
        }
        count += sampL.length;
    
      }
    
    
      //if I understand this correctly, UGens operate on a per sample basis
      Override
      protected void uGenerate(float[] channels) 
      {
        if (count > 0) {
          for(int n = 0; n <channels.length; n++){
           channels[n] = ((n&1) == 0)?left[outpos]:right[outpos]; 
          }
          outpos++;
          if (outpos == buffer_max) {
             outpos = 0;
           }
          count--;
        }
    
      }
    
    }
    

    Use like this:

    import ddf.minim.*;
    
    Minim minim;
    AudioInput in;
    AudioOutput out;
    MyAudioSocket mySocket;
    
    void setup()
    {
      size(512, 200);
    
      minim = new Minim(this);
      minim.debugOn();
    
      // get a line in from Minim, default bit depth is 16
      int buffer_size = 4096;
      in = minim.getLineIn(Minim.STEREO, buffer_size);
      out = minim.getLineOut(Minim.STEREO, buffer_size);
    
      // Create the socket to connect input to output
      mySocket = new MyAudioSocket(buffer_size);
      // Connect the socket as a "listener" for the line-in
      in.addListener(mySocket);
      //patch directly out, but you can patch into another UGen first
      mySocket.patch(out);
    
    }
    
    void draw()
    {
    // erase the window to black
      background( 0 );
      // draw using a white stroke
      stroke( 255 );
      // draw the waveforms
      for( int i = 0; i < out.bufferSize() - 1; i++ )
      {
        // find the x position of each buffer value
        float x1  =  map( i, 0, out.bufferSize(), 0, width );
        float x2  =  map( i+1, 0, out.bufferSize(), 0, width );
        // draw a line from one buffer position to the next for both channels
        line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50);
        line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50);
      } 
    }
    
  • Hello,

    I am using your code and am wondering if there would be anyway to manipulate the audio in before playing it back in the echo.

    Thanks.

Sign In or Register to comment.