Using ugens to write to WAV in non-realtime

edited September 2016 in Library Questions

I am trying to adapt a sketch I made using minim in realtime to write a WAV offline (not in real-time). I have come across examples using the javasound api to write a WAV from an array where a sine table is generated byte-by-byte, but I would like to use unit-generator based sound libraries like minim or jsyn to generate the audio data. Since those libraries are mainly used for realtime synthesis to an audio device, I am confused about how this would be accomplished.

One thing that sticks out in my mind is that in minim (I am less familiar with jsyn), I assume that chunks of data are written to the output stream consisting of multiple samples per draw() loop frame. I am just generally unsure of how to capture these frames to a buffer to write a file, or better to a stream that java can use to write the file piece by piece.

Sorry if this is vague, I am a bit lost in general regarding the architecture of these libraries and don;t have an understanding of what the bits and pieces are that would get unit generators working to write data in a non-realtime application.

Thanks for any help in advance, I can provide some of the code that I have worked on if that would clarify things.

Answers

  • edited September 2016

    @gordano -- re: "Since those libraries are mainly used for realtime synthesis to an audio device, I am confused about how this would be accomplished."

    Can you provide a minimal complete example sketch (mcve) that show what you are trying to adapt from real-time to write-offline paradigm? This might even be a base minim example, and then showing what you are attempting to accomplish concretely. That might be better than providing a large work you are adapting.

    Keep in mind that draw() is just (well, mostly) a function that is called periodically at frameRate. You can put writing commands in setup, in other functions, or in loops that are not based on frameRate or millis(). Have you tried doing this an encountered problems?

  • edited September 2016

    Here is an example sketch:

    import ddf.minim.*;
    import ddf.minim.signals.*;
    Minim minim;
    AudioOutput out;
    
    int banksize = 60;
    int seconds = 10;
    int frames = seconds * 60; //60 = approx framerate
    float[][] terrain = new float[frames][banksize]; 
    SineWave[] bank = new SineWave[banksize];
    float startingFreq = 200; 
    int interval = 18; //higher = smaller osc interval
    float lev;
    int counter = 0;
    
    void setup(){
    
    size(500,500);
    minim = new Minim(this);
    out = minim.getLineOut();
    
    // fill terrain array  
    for(int i = 0; i < frames; i++ ){
     for(int j = 0; j < banksize; j++ ){ 
       terrain[i][j] = noise(i/20.0, j/10.0);  
     }
    }
    
    // init sinebank
    float freqInt = startingFreq;
    for (int i = 0; i < banksize; i++)
    { 
      freqInt+=freqInt/interval;
      bank[i] = new SineWave(freqInt, 0.5/banksize,44100);
      out.addSignal(bank[i]);
    }
    
    }
    
    void draw(){
    
    background(200);
    //for ~10 seconds
    if(counter+1 < frames){
      //update sinebank each frame
      for(int i=0; i<banksize; i++){ 
        lev = pow(terrain[counter][i], 4);
        bank[i].setAmp(lev/6);
        point(i*3,height/2-lev*200);
     }
    
      counter++;   
    
    }
    else{
     out.clearSignals(); 
    }
    
    
    }
    

    It makes a 2d perlin noise array in setup(), and in draw() plays sound, using the shape of the noise array in that frame to control the "spectrum" of an array of sine oscillators. The code I'm adapting is a little different, but has the same idea of converting data into spectral audio over time.

    The idea would be to move the part inside draw() into setup() basically, to spit out a wav file, but as far as i know, minim is meant to be in draw() so it can generate sound for every frame behind the scenes. I could just build my own array of lookup tables and not use minim at all, but since it is simple is making the sound I want, and is already creating a buffer of audio data somewhere I was hoping I could adapt minim or jsyn somehow.

    Edit: here is a forum post I found that shows how to write a .wav from an array: https://forum.processing.org/two/discussion/4339/how-to-save-a-wav-file-using-audiosystem-and-audioinputstream-of-javasound

  • edited September 2016

    @gordano -- if I understand (and I am not a minim expert) you are interested in non-realtime analysis.

    1. Check out this documentation on using minim for non-realtime analysis with loadFileStream
    2. See if this discussion of Non-Real Time Analysis and Rendering with minim and Processing helps.
    3. A very old discussion of minim non-realtime buffer access

    (Requesting a non-realtime demo sketch has been an open issue for minim for over a year now.)

    Does this put you on the right track? If not, perhaps a minim expert on the forum can weigh in.

  • I don't need non-realtime analysis since I have a "pre-analyzed" array. What I want to do is basically the reverse of that example. Take data and generate an audio file.

  • Perhaps check out Creating, processing and saving sound-buffers in Minim.

    for saving to disk, you'll have to get a bit trickier. You will need to write a class that implements the Recordable interface and then pass an instance of that to the createRecorder method of Minim. The AudioRecorder will set itself as an AudioListener to your Recordable instance and when you are ready to save samples to disk, you simply call the samples method of the listener. You could either choose to do this in chunks, like with FFT and effects processing, or you could choose to write the entire buffer at once. Whichever you choose, you simply need to make sure that the value returned by the bufferSize method of your Recordable instance is the same as the length of the float array you pass to the samples method. All of this makes me think I should just write a saveFile method for Minim.

    Might want to contact the author directly.

  • Thanks. Yes that looks like what I was expecting. It doesn't look like something I will be able to wrap my head around soon, so it might be better to write my own lookup table oscillator class instead of trying to that out. I still think it would be a useful thing to work out but without a better understanding of how minim or jsyn works I think it's not going to be easy.

  • @gordano -- good luck with it. It might be worth trying to contact the author about this question, on github or even on this forum.

Sign In or Register to comment.