How can I detect a custom event while the draw method is still running?(See Description)

I am using processing 2.2.1 with minim and writing code in java with netbeans. I have a situation where my processing sketch is running that means the draw method is running. While it is running an event is triggered by other class. For that I wrote a custom event handler and registered it in the class which is running the sketch..But the class is unable to detect the event..Any help..TIA

Answers

  • edited April 2017

    Processing has its own event handling thread which is separate from the NetBeans event handling thread. Effectively you have two applications running in one window. NOTE regular Java applications have just a single event handling thread.

    You might investigate a Java library called "EventsOnFire", it provides asynchronous event handling. I used it in the QScript library to fire events in one thread to be detected by Processing's event handling thread. Alternatively, if you are using NetBeans with Java 8 then you could try using JavaBeans to _bind _2 variables (one from each thread) and then a change handler in the class receiving the new value.

    Whatever you use you will have to be careful that communicating between threads does not cause concurrent access exceptions.

    If you don't need the Processing sketch to interact with the mouse or keyboard in other words just using it to display some graphics you could stop its event loop with noLoop() and the create a Java Swing timer to call redraw() every 17 ms (60 fps). That way there is just a single event thread (NetBeans) so simplifies the problem.

  • @quark Considering your answer, I would like to share what I have done-- I wrote a custom event handler for receiving a file over socket..The class which is drawing my processing sketch implements that listener and toggle a variable from true to false--for example-fileReceiveStatus..When the draw function is running I received a file and update the variable to true..My listener is also updating the variable..But If I keep a check on the variable in the draw() method it does not detect that the variable is updated to true from false...That's what my problem is..

  • Perhaps it detects so in the next frame?

  • edited April 2017

    ... you could stop its event loop with noLoop() and the create a Java Swing timer to call redraw() every 17 ms (60 fps).

    @quark, noLoop() can't even stop the "Animation Thread", much less the "AWT-EventQueue-0"! :-@

    It merely sets field looping to false: if (!looping) looping = true;
    https://GitHub.com/processing/processing/blob/master/core/src/processing/core/PApplet.java#L2519-L2523

    When the "Animation Thread" executes handleDraw(), it returns prematurely if looping is false: if (!looping && !redraw) return;
    https://GitHub.com/processing/processing/blob/master/core/src/processing/core/PApplet.java#L2356-L2361

    In short, neither threads ever stop. "Animation Thread" enters "standby", while "AWT-EventQueue-0" still keeps on checking for input events even when the former is "paused". B-)

    So each "ignited" PApplet creates 2 Thread instances, not just 1.
    "AWT-EventQueue-0" enqueues all user input events, while the "Animation Thread" dequeues them. :)>-

  • Then is it be possible to make some ^small^ changes to be able to add your own events?

  • Yes forget what I said about using noLoop etc.

    My listener is also updating the variable..

    Are you sure? Have you println it out?

    But If I keep a check on the variable in the draw() method it does not detect that the variable is updated to true from false

    If it is changing but the change is not being seen in draw() then they can't both be looking at the same variable, its impossible!

  • edited April 2017

    Some extra corrections for the other renderers though. :-\"

    "Animation Thread" & "AWT-EventQueue-0" are for the default renderer JAVA2D only! ~:>

    For P2D & P3D, those threads are respectively:

    1. "main-FPSAWTAnimator#00-Timer0-FPSAWTAnimator#00-Timer1"
    2. "main-Display-.windows_nil-1-EDT-1".

    And it seems like FX2D got 1 Thread only: "JavaFX Application Thread". @-)

  • edited April 2017

    Yes, forget what I said about using noLoop(), etc.

    @quark, it's still immensely useful to use noLoop() when it's not needed, b/c it stops the constant 60 FPS rendering, saving both CPU & GPU, even though the threads are still alive! O:-)

  • ... it does not detect that the variable is updated to true from false...

    Make sure there's only 1 boolean variable w/ declared w/ that name as a PApplet field.
    If it's still not working, declare it as volatile as well. :ar!

  • edited April 2017

    I posted some code here which allows the user to see what threads are in existence at runtime. Might be useful to someone.

    The reason for using noLoop() and redraw() was to bring the drawing of the sketch to be executed inside the main AWT event thread. I think the redraw() method simply 'invites' the applet to execute draw() at the next opportunity. If true then it is still inside the Processing thread so it would not do what I hoped.

    Might be worth trying but call the darw() method directly from the Swing timer. May or may not work I have no ides but probably worth trying.

  • edited April 2017

    Might be worth trying but call the draw() method directly from the Swing timer.

    @quark, seems like you didn't pay attention on this statement at the beginning of handleDraw():
    if (!looping && !redraw) return;

    As I have stated in my 1st reply here, handleDraw() merely quits prematurely after checking out those 2 boolean fields.

    It's useless to directly invoke draw() b/c it won't trigger the PSurface to render the current content of main canvas PGraphics. 8-X

  • edited April 2017

    The reason for using noLoop() and redraw() was to bring the drawing of the sketch to be executed inside the main AWT event thread.

    Even when noLoop() is active, draw() is still executed under the "Animation Thread" after redraw().

    Although inside input event callbacks, it's the "AWT-EventQueue-0" Thread which executes them:

    void setup() {
      size(300, 200, JAVA2D);
      noLoop();
      frameRate(1);
      println(Thread.currentThread()); // Thread[Animation Thread,5,main] 
    }
    
    void draw() {
      background((color) random(#000000));
      println(Thread.currentThread(), ENTER); // Thread[Animation Thread,5,main] 
    }
    
    void mousePressed() {
      println(Thread.currentThread()); // Thread[AWT-EventQueue-0,6,main]
      redraw();
    }
    
  • I made some off-the-cuff remarks without thinking them through so I have crossed out all the extraneous comments, leaving the stuff I am happy to have said. :D

    It might get us back to the OP's original problem.

  • edited April 2017

    I think code sharing might be of some help...Sorry for some unused code...If you could kindly take time to see the code and give me solution...

    TIA

    In Client.java I made the gui to load the processing sketch..I made a custom event listener to trigger when a file is received...I have an interface FileReceivingListener..Then the dessign.java class which does the work for spectrum analysis and implemetns the interface..

    Client.java

    
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.io.BufferedOutputStream;
    import java.io.DataInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.Socket;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import static multithreadeduser.SpectrumofAudio.frame;
    import processing.core.PFont;
    
    /**
     *
     * @ author Hp
     */
    public class Client {
    
        public final static int SOCKET_PORT = 8000;      // you may change this
        public final static String SERVER = "Localhost";  // localhost
        public static String FILE_TO_RECEIVED = "";  // you may change this, I give a
        public final static int FILE_SIZE = 81205209;
        private FileReceivedListener listener;
        static Dessign dsgn;
    
        static JPanel panelForProcessing;
        static JPanel panelForBtn;
        static JFrame frame;
        static JButton scanBtn;
        Dessign psketch = new Dessign();
    
        public void connectionsss() throws IOException {
            Socket sock = null;
    
            try {
    //            ServerFrame s=new ServerFrame();
    //            s.serverstart(SOCKET_PORT);
                sock = new Socket(SERVER, SOCKET_PORT);
                DataInputStream din = new DataInputStream(sock.getInputStream());
                FILE_TO_RECEIVED = din.readUTF();
                System.out.println("file name....." + FILE_TO_RECEIVED);
                dsgn = new Dessign();
                dsgn.getFileName(FILE_TO_RECEIVED);
                //psketch.start();
                listener.ListenFileReceive();
                
              
                
            } catch (Exception e) {
            }
    
        }
    
        
        public void initGuiForProcessing() {
            frame = new JFrame("processing in frame");
            panelForProcessing = new JPanel();
            panelForBtn = new JPanel();
            scanBtn = new JButton("Scan");
    
            //psketch.getFileName(fName);
            //scanbtn properties
            scanBtn.setPreferredSize(new Dimension(80, 30));
            scanBtn.setFont(scanBtn.getFont().deriveFont(Font.BOLD));
            scanBtn.setActionCommand("scan");
            scanBtn.addActionListener(psketch);
            //scanBtn.setBorder(new LineBorder(Color.black));
            psketch.init();
            
    
            panelForProcessing.setBackground(Color.BLACK);
            panelForProcessing.add(psketch);
            //panelForBtn.setLayout(null);
            panelForBtn.setBounds(0, 230, 600, 500 - 220);
            panelForBtn.add(scanBtn);
            frame.add(panelForBtn);
            frame.add(panelForProcessing);
            //System.out.println(d.getSize().width+"  "+d.getSize().height);
            frame.setSize(600, 500);
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        public static void main(String[] args) {
            Client cf = new Client();
            cf.initGuiForProcessing();
            dsgn = new Dessign();
            cf.listener = dsgn;
            // SpectrumofAudio sA = new SpectrumofAudio();
    //                cf.setVisible(false);
            try {
    
                while (true) {
                    cf.connectionsss();
    
                }
            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    
    }
    
    

    dessign.java

    import ddf.minim.AudioInput;
    import ddf.minim.AudioPlayer;
    import ddf.minim.Minim;
    import ddf.minim.analysis.FFT;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.File;
    import javax.swing.JFrame;
    import processing.core.PApplet;
    import static processing.core.PConstants.CENTER;
    import static processing.core.PConstants.RIGHT;
    import static processing.core.PConstants.TOP;
    
    /**
     *
     * @ author mezbahuddin
     */
    public class Dessign extends PApplet implements ActionListener, FileReceivedListener {
    
        String fileToPlay;
        Minim minim;
        AudioInput in;
        FFT fft;
        FFT fft2;
        AudioPlayer ap;
        AudioPlayer ap2;
         boolean fileReceived;
    
        float gain = 0; // in dB
        float dB_scale = (float) 2.0;  // pixels per dB
        int buffer_size = 1024;  // also sets FFT size (frequency resolution)
        float sample_rate = 44100;
    
        int spectrum_height = 200; // determines range of dB shown
        int legend_height = 20;
        int spectrum_width = 512; // determines how much of spectrum we see
        int legend_width = 40;
        int freqOffset = 0;
        //boolean startScan;
        String complete = "";
    
        public void getFileName(String name) {
            //fileToPlay = "E:\\";
            fileToPlay = name;
    
            
            String sPortion = "";
            while (true) {
                int indx = fileToPlay.indexOf("\\");
                if (indx < 0) {
                    break;
                }
                String fPortion = fileToPlay.substring(0, indx + 1);
                sPortion = fileToPlay.substring(indx + 1, fileToPlay.length());
                fPortion += "\\";
                complete += fPortion;
                fileToPlay = sPortion;
            }
            complete += sPortion;
            System.out.println("Dessign----" + complete);
            initializeFile(complete);
    
        }
    
        // how many individual peak bands we have (dep. binsperband)
        public void settings() {
            size(552, 220, "1processing.opengl.PGraphics2D");
        }
    
        public void setup() {
            //size(552, 220, "1processing.opengl.PGraphics2D");
            size(552, 220, P2D);
            //textMode(SCREEN);
            textFont(createFont("Georgia", 12));
    
            //println("buffer:"+in.bufferSize());
            //println("sampleRate:"+in.sampleRate());
            //println("peaksize:"+peaksize);
            //fileReceived = false;
    
        }
    
        public void DrawAxes(int freqOffset) {
            background(0);
            fill(255);
            stroke(255);
    
            int y = spectrum_height;
    
            line(legend_width, y, legend_width + spectrum_width, y); // horizontal line
    
            // x,y address of text is immediately to the left of the middle of the letters 
            textAlign(CENTER, TOP);
    
            int spFreq = 0; //for spacing
    
            for (float freq = (float) 0.0; freq < 44100; freq += 2000.0) {
                int x = legend_width + spFreq + freqOffset; // which bin holds this frequency
                //println(freq+"->"+fft.freqToIndex(freq));
                line(x, y, x, y + 4); // tick mark
                text(Math.round(freq / 1000) + "kHz", x, y + 5); // add text label
                spFreq += 45;
            }
    
            // DBlevel axis
            int x = legend_width;
    
            line(x, 0, x, spectrum_height); // vertictal line
    
            textAlign(RIGHT, CENTER);
    
            for (float level = (float) -100.0; level < 100.0; level += 20.0) {
                y = spectrum_height - (int) (dB_scale * (level + gain));
    
                line(x, y, x - 3, y);
    
                text((int) level + " dB", x - 5, y);
            }
    
        }
    
        public void initializeFile(String fileName) {
    
            System.out.println("initFILE:"+fileName);
            minim = new Minim(this);
            ap2 = minim.loadFile(fileName);
            
            // create an FFT object that has a time-domain buffer 
            // the same size as line-in's sample buffer
            //fft = new FFT(ap.bufferSize(), ap.sampleRate());
            fft2 = new FFT(ap2.bufferSize(), ap2.sampleRate());
    
            // Tapered window important for log-domain display
            fft2.window(FFT.HAMMING);
            
    
        }
    
        public void draw() {
            DrawAxes(freqOffset);
            System.out.println(fileReceived);
         if (fileReceived) {
                DrawAxes(freqOffset);
                System.out.println("here");
                // background(0);
                // perform a forward FFT on the samples in input buffer
                //fft.forward(ap.mix);
                fft2.forward(ap2.mix);
    
                ap2.play();
    
                // now draw current spectrum in brighter blue
                stroke(64, 255, 255);
                noFill();
    
                for (int i = 0; i < fft2.specSize(); i++) {
    
                    // draw the line for frequency band i using dB scale
                    float val = dB_scale * (20 * ((float) Math.log10(fft2.getBand(i))) + gain);
    
                    if (fft2.getBand(i) == 0) {
                        val = -200;
                    }  // avoid log(0)
    
                    int ab = spectrum_height - Math.round(val);
    
                    if (ab > spectrum_height) {
                        ab = spectrum_height;
                    }
    
                    line(legend_width + i + freqOffset, spectrum_height, legend_width + i + freqOffset, ab);
    
                    // update the peak record
                    // which peak bin are we in?
                    //int peaksi = i/binsperband;
                    //if (val > peaks[peaksi]) {
                    //  peaks[peaksi] = val;
                    //  // reset peak age counter
                    //  peak_age[peaksi] = 0;
                    //}
                }
            }
    
    //  // clear window
    //
    //  // add legend
    //  // frequency axis
        }
    
        public void keyReleased() {
            // +/- used to adjust gain on the fly
            if (key == '+' || key == '=') {
                gain = (float) (gain + 5.0);
            } else if (key == '-' || key == '_') {
                gain = (float) (gain - 5.0);
            } //(.)/(/) used to adjust frequency axis
            else if (key == '/') {
                freqOffset = freqOffset - 4;
            } else if (key == '.') {
                freqOffset = freqOffset + 4;
            }
        }
    
        public void stop() {
            // always close Minim audio classes when you finish with them
            in.close();
            ap2.close();
            minim.stop();
            this.noLoop();
            super.stop();
        }
    
        @ Override
        public void actionPerformed(ActionEvent ev) {
            if (ev.getActionCommand().equals("scan")) {
                
            }
        }
    
        @ Override
        public void ListenFileReceive() {
            System.out.println("in listener of DESSIGN");
            fileReceived = true;
            System.out.println(fileReceived);
            
        }
        
    }
    
    

    I printed the fileReceived boolean variable in draw..but its always false... Apologies for posting long codes..But I'm stuck here badly :( @quark @GoToLoop

  • Answer ✓

    Things to try.

    1) Add a log info report for the catch clause in line 53/54 of the Client class. Are any exceptions being thrown here? I think you might have some other exceptions that you are not detecting. Either that or the connectionsss method never throws an IO exception because it is being caught and ignored in the try/catch. (in which case you don't get to see any output from (3) below.

    2) Are the statements in line 222 & 224 of the Dessign class printing anything?, any why not use the logger?

    3) Add a log info report in actionPerformed method line 216. Might as well test that as well.

    Just noticed what else might be a problem.

    In static void main you create a Dessign object and add a listener but then replace it in the connectionsss() method. NOT a good idea since this class is your main PApplet class, in other words effectively a Processing sketch. There should only be ONE Dessign class object instantiated.

  • At last solved.. thanks @quark... Problem was: I was instantiating multiple object and trying to work them on the single processing sketch..Now I instantiated one object and used it for listener and sketch and wherever I needed..I guess it was silly programming error. :p

Sign In or Register to comment.