SelectOutput doesn't have any effect

edited October 2017 in Library Questions

I have modified a sketch which records sound and saves it on harddrive. In the setup-function, i call the selectOutput function. When i run the sketch, i can choose an output-file, but the data get saved in the default-output-file, which i have specified above the setup-function. Why does selectOutput have no effect on the output-file?

Here is the complete code:

 import ddf.minim.*;

    Minim minim;
    AudioInput in;
    AudioRecorder recorder;
    String absoluterPfad = "/home/karl-alfred/Schreibtisch/myrecording.wav";

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

      minim = new Minim(this);

      in = minim.getLineIn();
      // create a recorder that will record from the input to the filename specified
      // the file will be located in the sketch's root folder.
      selectOutput("Select a file to process:", "fileSelected");
      recorder = minim.createRecorder(in, absoluterPfad);
      textFont(createFont("Arial", 12));
    }

     void fileSelected(File selection) {
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
      } else {
        println("User selected " + selection.getAbsolutePath());
       absoluterPfad = selection.getAbsolutePath();
       println ("Absoluter Pfad: " + absoluterPfad);
      }
    }


    void draw()
    {
      background(0); 
      stroke(255);
      // draw the waveforms
      // the values returned by left.get() and right.get() will be between -1 and 1,
      // so we need to scale them up to see the waveform
      for(int i = 0; i < in.bufferSize() - 1; i++)
      {
        line(i, 50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50);
        line(i, 150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50);
      }

      if ( recorder.isRecording() )
      {
        text("Currently recording...", 5, 15);
      }
      else
      {
        text("Not recording.", 5, 15);
      }
    }

    void keyReleased()
    {
      if ( key == 'r' ) 
      {
        // to indicate that you want to start or stop capturing audio data, you must call
        // beginRecord() and endRecord() on the AudioRecorder object. You can start and stop
        // as many times as you like, the audio data will be appended to the end of whatever 
        // has been recorded so far.
        if ( recorder.isRecording() ) 
        {
          recorder.endRecord();
        }
        else 
        {
          recorder.beginRecord();
        }
      }
      if ( key == 's' )
      {
        // we've filled the file out buffer, 
        // now write it to the file we specified in createRecorder
        // the method returns the recorded audio as an AudioRecording, 
        // see the example  AudioRecorder >> RecordAndPlayback for more about that
        recorder.save();
        println("Done saving.");
      }
    }

Answers

  • edit post, highlight code, press ctrl-o

    that's probably the 5th time today i've typed that. do people not check what they post?

  • edited October 2017

    Thanks koogs. Looks much nicer.

    • selectOutput(), and similar, doesn't block the execution flow.
    • That is, the sketch doesn't await for a user to choose a path!
    • When variable absoluterPfad is passed as the 2nd argument for createRecorder(), it still has its initial String value.
  • Thanks GoToLoop. Yes it seems so. The program jumps to row 18 before 17 is finished. But how can i change that?

  • edited October 2017 Answer ✓

    But how can I change that?

    • You can't change it (at least not w/o some hardcore hack)! But you can workaround that. :ar!
    • Inside fileSelected(), which is called back by selectOutput(), you reassign variable absoluterPfad, right?
    • So that reassignment signals that fileSelected() has done its job. :-?
    • Therefore we've got some strategy in mind already: Let's await for absoluterPfad to have a diff. value! *-:)
    • In order to await for that reassignment event to occur, we can have an "infinite" loop which breaks itself free only when absoluterPfad doesn't have its old value anymore.
    • However, an "infinite" loop which keeps checking out some condition non-stop is very stressful for the CPU, and it can literally "fry" it! :-SS
    • In order to force a momentary pause between each loop iteration condition check, we can use delay() w/ a small napTime value (something like 1 to 10): https://Processing.org/reference/delay_.html
    • So the plan is the following: Cache the current value of absoluterPfad.
    • Then right after invoking selectOutput(), start an "infinite" loop which keeps checking out whether absoluterPfad is still equal to its old cached value.

    final String cachedPath = absoluterPfad;
    selectOutput("Select a file to process:", "fileSelected");
    for (; absoluterPfad == cachedPath; delay(5));
    recorder = minim.createRecorder(in, absoluterPfad);
    
  • Wow, that's a really tricky solution. It works fine, but i still haven't understood, why it works. Maybe in a couple of days. Thank you very much!!!

  • edited October 2017 Answer ✓

    ... but i still haven't understood, why it works.

    • selectOutput() & similar functions create another Thread:
      http://Docs.Oracle.com/javase/8/docs/api/java/lang/Thread.html
    • Each Thread executes a line of code at the same time as other Threads.
    • What I did was halting Processing's Thread to await until selectOutput()'s Thread finishes its task.
    • Which is assigning a path String to variable absoluterPfad.
  • edited October 2017

    If selectOutput has its own thread, the strange behavior and your 'trick' ist plausible. Thank you GoToLoop. :)

    I have changed your for-loop to a while-loop, which is more intuitive for me: while(absoluterPfad == cachedPath){delay(5);}

  • edited October 2017 Answer ✓

    I have changed your for-loop to a while-loop, which is more intuitive for me:

    while (absoluterPfad == cachedPath) {
      delay(5);
    }
    

    Well, I've just mentioned an "infinite" loop. L-)
    Whether that's implemented via a for () or while (), that's your pick. :>

    Anyways, for completeness' sake, gonna repost my own version, but w/ 1 line less.
    This time, line #1, which declares & initializes variable cachedPath, goes into the for () loop itself: :\">

    selectOutput("Select a file to process:", "fileSelected");
    for (final String cachedPath = absoluterPfad; absoluterPfad == cachedPath; delay(5));
    recorder = minim.createRecorder(in, absoluterPfad);
    
  • That's brilliant, but it would be to complex for me to understand.

  • One last question:

    selectOutput() & similar functions create another Thread:

    How can i determine, that a command creates a new thread?

  • Answer ✓

    Well, the fact the program doesn't wait for a function to fully finish its job is a strong indicative.
    Another way is studying the function's source code. >-)

  • Another way is studying the function's source code.

    OMG :-B

  • edited October 2017 Answer ✓

    There's an easier 1. The documentation may hint about it as a footnote: :(|)
    https://Processing.org/reference/selectOutput_.html

    The callback is necessary because of how threading works.

  • Answer ✓

    And speaking about callbacks, that's a strong indicative that's gonna happen in another Thread. Although not always... I-)

  • How can i determine, that a command creates a new thread?

    In Processing very few commands work in this way -- and the ones that do generally deal with file input / output. As @GoToLoop points out, passing a callback is a big hint.

    Also, thread():

Sign In or Register to comment.