ADSR and playNote with Minim

Hi, I’m having troubles figuring out how to do something with minim.
In the ADSR example, we have this:

    // new ADSR(amp, atk, sus, dec, rel)
    adsr = new ADSR( 0.5, 0.01, 0.05, 0.5, 0.5 );

However, to call the Instrument we have this:

    // playNote(init time, duration in beats, instrument)
    out.playNote( 1.25 + i*2.0, 0.3, new ToneInstrument( 75, 0.49 ) );

I find out that the “duration” in the playNote is affecting the ADSR! I don’t wan’t this, I just wan’t it to play the wave and keep the values of the ADSR, how can I achieve this? I’ve tried calculating the duration on the note based on atk, dec, sus, rel but still seems that it’s not the way it should be. How can I play the note without a prefixed duration?

Also, I’ve found out that if I don’t create the Instrument right inside of playNote (for example, creating the instrument inside and array and then calling it), bizarre behaviour occurs, it is mandatory to only make the new instance of instruments inside the playNote?

Thanks.

hi, a very tricky question,
and if you put some more effort in it
to give us something ready to play with, to understand,
would have been appreciated

so i start from minim ADSR example ( possibly like you )
but work it over and check documentation
and replaced the bunch of numbers with readable variables.

/* MINIM ADSRExample */
// http://code.compartmental.net/minim/adsr_class_adsr.html
// http://code.compartmental.net/minim-beta/documentation/audiooutput_method_playnote.htm
// https://discourse.processing.org/t/adsr-and-playnote-with-minim/16057

import ddf.minim.*;
import ddf.minim.ugens.*;

Minim minim;
AudioOutput out;

class ToneInstrument implements Instrument {
  Oscil sineOsc;
  ADSR  adsr;
  float maxAmp= 0.5, attTime=0.01, decTime=0.05, susLvl = 0.01/*0.5*/, relTime = 0.5;  
  ToneInstrument( float frequency, float amplitude ) {    
    sineOsc = new Oscil( frequency, amplitude, Waves.SINE );
    adsr = new ADSR( maxAmp, attTime, decTime, susLvl, relTime );
    sineOsc.patch( adsr );
  }

  void noteOn( float dur ) {
    adsr.noteOn();
    adsr.patch( out );
   }
  void noteOff() {
    adsr.unpatchAfterRelease( out );
    adsr.noteOff();
  }
}

void setup() {
  size( 512, 200, P2D );
  minim = new Minim( this );
  out = minim.getLineOut( Minim.MONO, 2048 );
  out.pauseNotes();
  println("use key [ ]");
}

void draw() {
  background( 0 );
  plot();
}

void keyPressed() {
  if ( key == ' ' ) play4( 440 );  
}

void play4(float hz) {
  println("play 4 notes "+hz+" hz");
  float amp = 0.5;
  float startTime=1, beat=2, duration=1; //sec
  for( int i = 0; i < 4; i++ )
    out.playNote( startTime + i*beat, duration, new ToneInstrument( hz, amp ) );
  out.resumeNotes();
}

void plot() {
  stroke( 255 );
  for( int i = 0; i < out.bufferSize() - 1; i++ ) {
    float x1  =  map( i, 0, out.bufferSize(), 0, width );
    float x2  =  map( i+1, 0, out.bufferSize(), 0, width );
    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);
  }  
}

yes, you are right, it is not possible to use the

playNote(startTime, duration, instrument);

without duration, so it is not meant to play ADSR as is.

so you find a other way to play the instrument and make your own timing.


still i was able to betray that whole construct,
when, like in my above code, use

susLvl = 0.01/*0.5*/

make the Sustain tone low its
overwritten duration does not matter, works like a pause.

just a hack…

2 Likes

Really - we only want to use the oscillators for starting a note within a given keyPressed procedure/event, then listening it at its sustain level, and finally stop it from a corresponding keyReleased event procedure… as it is technically known for a ADSR envelope.

In this regard, the fixed time “susLvl” is a problem, because the note duration isn’t known at a time when you start pressing a piano key… That’s why we cannot use this library for creating a MIDI instrument.