Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

  • APDE Tabs order

    I noticed that I can use even functions like setup() and draw() and event driven functions like mouse or bluetooth functions in random order. But this seems not to be true for java lifecycle functions like onCreate onStrart untill onStop. They must be on top of the sketch. Is that correct?

    PS For those working with APDE, as a temporary solution I found that if you transfer your sketch file to a desktop and rename it, than transfer back again; the tabs will be in alphabetic order.

  • Scrollable image with ScrollView

    A new demo. If you load images from internet, you need the internet permission.

    Kf

    //===========================================================================
        // IMPORTS:
    
    import android.app.Activity;
    import android.content.Context;
    import android.widget.FrameLayout;
    //import android.app.Fragment;
    
    import android.os.Environment;
    import android.graphics.Color;
    import android.widget.Toast;
    import android.os.Looper;
    import android.view.WindowManager;
    import android.os.Bundle;
    import android.view.ViewParent;
    import android.view.ViewGroup;
    import android.view.View;
    import android.widget.RelativeLayout;
    import android.widget.LinearLayout;
    import android.view.LayoutInflater;
    import android.R.string;
    
    import android.R;
    import android.widget.ImageView;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.util.Log;
    import android.widget.ScrollView;
    import android.widget.Button;
    
    
        //===========================================================================
    // FINAL FIELDS:
    final int imageID=12345;
    
    //===========================================================================
    // GLOBAL VARIABLES:
    
    Activity act;
    Context mC;
    
    FrameLayout fl;
    ScrollView sv;
    int imageID1=-1;
    int imageID2=-1;
    int imageID3=-1;
    
    
    ArrayList<PImage> imgCon;
    
    PImage img1, img2, img3;
    int currIdx=-1;
    
    
    //===========================================================================
    // PROCESSING DEFAULT FUNCTIONS:
    
    void setup() {
      fullScreen();
      orientation(PORTRAIT);
    
      act = this.getActivity();
      Looper.prepare();
    
      textAlign(CENTER, CENTER);
    
      fill(255);
      strokeWeight(2);
      textSize(32);
    
      imgCon = new ArrayList<PImage>();
    
      imgCon.add(initImage(width, int(height*0.80), "KlEo"));
      imgCon.add(initImage(width, int(height*1.25), "xSiNe")); 
      imgCon.add(initImage(width, int(height*1.50), "DRAkeN")); 
    
      //  *****  FOR the next images one needs to enable INTERNET permissions
    
      //PImage extra1=requestImage("https://vignette.wikia.nocookie.net/vsbattles/images/a/ad/Alduin.jpg/revision/latest?cb=20140811032839");  //dragon
      PImage extra2=requestImage("https://upload.wikimedia.org/wikipedia/commons/c/ce/Black-headed_oriole,_Oriolus_larvatus,_at_Mapungubwe_National_Park,_Limpopo,_South_Africa_(18201359415).jpg");  //Yellow bird
      PImage extra3=requestImage("http://78.media.tumblr.com/ff9912bcaa6963631a6a205ae7be46a5/tumblr_mxarraaVgz1shaozko1_1280.jpg");
      PImage extra4=requestImage("http://www.shorpy.com/files/images/SHORPY_4a08044a.jpg");  //NY building
    
      while ( extra2.width<=1 || extra3.width<=1 || extra4.width<=1 ) {
        if(frameCount%90==0) println(extra2.width,extra3.width,extra4.width);
        delay(50);
      }
    
    
      extra2.loadPixels();
      extra2=extra2.get(0, 0, min(width, extra2.width), extra2.height);
      extra2.updatePixels();
    
      extra3.loadPixels();
      extra3=extra3.get(0, 0, width, extra3.height);
      //extra3.resize(width, extra3.height);
      extra3.updatePixels();
    
      //imgCon.add(extra1);
      imgCon.add(extra2);
      imgCon.add(extra3);
      imgCon.add(extra4);
      //imgCon.add(extra5);
    
      for (PImage q : imgCon) {
        println(q.width, q.height);
      }
    
    
      currIdx=0;
      swapImage();
    }
    
    void draw() {
    
      text("Scroll View Demo showing now "+currIdx, width>>1, height/40.0);
      text("Size of selected iamge "+imgCon.get(currIdx).width+"x"+imgCon.get(currIdx).height, width>>1, height/16.0);
    }
    
    void mouseReleased() {
      //swapImage();
    }
    
    void swapImage() {
    
      background(random(70, 144));
      currIdx=(currIdx+1)%imgCon.size();
    
      act.runOnUiThread(new Runnable() {
        @ Override
          public void run() {
    
          ImageView imgv= (ImageView)  act.findViewById(imageID); 
          imgv.setImageBitmap((Bitmap)imgCon.get(currIdx).getNative());
        }
      }
      );
    }
    
    
    //===========================================================================
    // OTHER FUNCTIONS:
    
    //Creates an image with a color gradient as background and a ellipse of random size
    //placed at a random location. The label is placed inside the ellipse.
    PImage initImage(int w, int h, String label) {
      PImage aimg =createImage(w, h, ARGB);
    
      int s=w*h;
      float lower=random(225);
      float delta=25;
      colorMode(HSB, 255);
    
      aimg.loadPixels();
      for (int i=0; i<s; i++)
        aimg.pixels[i]=color(int(lower+delta*i*1.0/s), 255, 255);//color(random(upper), random(50, 200), random(upper,255));
      aimg.updatePixels();
    
      int diameter=int(w*random(0.35, 0.70));
      float px=random(diameter, width-diameter);
      float py=random(diameter, height-diameter);
    
      PGraphics con =createGraphics(w, h, JAVA2D);
      con.beginDraw();
      con.image(aimg, 0, 0);
    
      con.fill(255-lower, 250, 250);
      con.noStroke();
      con.ellipse(w-px, h-py, diameter/2.0, diameter/2.0);
      con.ellipse(px, py, diameter, diameter);
    
      con.textAlign(CENTER, CENTER);
      con.colorMode(HSB, 255);
      con.fill(lower, 255, 255);
      con.textSize(max(36, w/80.0));
      con.text(label, px, py);
      con.text(label, px+1, py+1);  //Bold effect
    
      con.endDraw();
      return con.get();
    }
    
    //===========================================================================
    // ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:
    
    
    //  @@@@@@@@@@@@
    @Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      act = this.getActivity();
      mC= act.getApplicationContext();
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
    
      Button switchButton= new Button(act);
      switchButton.setLayoutParams(new RelativeLayout.LayoutParams(width>>2,int(height/13.0)));
      switchButton.setTextSize(10);
      //switchButton.setTextColor(Color.rgb(220,220,220));
      switchButton.setText ("Next Image");
      switchButton.setX(width*0.60);
      switchButton.setY(height*0.1);
      switchButton.setOnClickListener(new View.OnClickListener(){    
        public void onClick(View V){ 
          swapImage(); 
        }
      });
    
      ImageView imgView = new ImageView(act);
      imgView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView.setId(imageID); //imgView1.generateViewId()
    
    
      LinearLayout linLay=new LinearLayout(act);
      linLay.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); 
      linLay.setOrientation(LinearLayout.VERTICAL);  
      linLay.addView(imgView);
    
     int svHeight=int(height*0.70);
      sv = new ScrollView(act);
      sv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, svHeight));  
      sv.setVerticalScrollBarEnabled(true);  
      sv.setY(height-svHeight);  
      sv.addView(linLay);
    
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
      //                 @@@@@@@@@@@@@@@@@@@@@@@@@@@
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
    
      fl = (FrameLayout)act.findViewById(R.id.content);
      fl.addView(switchButton);
      fl.addView(sv);
    }
    
  • Scrollable image with ScrollView

    Not sure what is causing the problem in your case. I just tested the app in an emulator and it worked. I have to say that my code was not adapted to different screen resolutions. I modified the code to do so. I notice there is also a bug/undesirable features that if you press on the upper section of your screen, it will trigger the button. Not a big deal in this demo, but it is still a pain the the place where everybody knows.

    Below it shows the scrolling action.

    Kf

    Screenshot_1521531922

    Screenshot_1521531925

    Screenshot_1521531928

    //===========================================================================
    // IMPORTS:
    
    import android.app.Activity;
    import android.content.Context;
    import android.widget.FrameLayout;
    //import android.app.Fragment;
    
    import android.os.Environment;
    import android.graphics.Color;
    import android.widget.Toast;
    import android.os.Looper;
    import android.view.WindowManager;
    import android.os.Bundle;
    import android.view.ViewParent;
    import android.view.ViewGroup;
    import android.view.View;
    import android.widget.RelativeLayout;
    import android.widget.LinearLayout;
    import android.view.LayoutInflater;
    import android.R.string;
    
    import android.R;
    import android.widget.ImageView;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.util.Log;
    import android.widget.ScrollView;
    import android.widget.Button;
    
    
    //===========================================================================
    // FINAL FIELDS:
    
    
    //===========================================================================
    // GLOBAL VARIABLES:
    
    Activity act;
    Context mC;
    
    FrameLayout fl;
    ScrollView sv;
    int imageID1=-1;
    int imageID2=-1;
    int imageID3=-1;
    
    PImage img1, img2, img3;
    int curr=-1;
    
    int basicImageSize=0;
    int thumbNailSize=0;
    
    //===========================================================================
    // PROCESSING DEFAULT FUNCTIONS:
    
    void setup() {
      fullScreen();
      orientation(PORTRAIT);
      //orientation(LANDSCAPE;)
    
      act = this.getActivity();
      Looper.prepare();
    
      textAlign(CENTER, CENTER);
      //rectMode(CENTER);
    
      fill(255);
      strokeWeight(2);
      textSize(max(16,width/30.0));
    
      basicImageSize=int(min(width,height)/4.0);
      thumbNailSize= int(basicImageSize/6.0);
    
    
    
      img1=initImage(basicImageSize*1, basicImageSize*3, ARGB);//loadImage("pic40.jpg");
      img2=initImage(basicImageSize*2, basicImageSize*3, ARGB); 
      img3=initImage(basicImageSize*3, basicImageSize*3, ARGB);
    
      curr=0;
    }
    
    void draw() {
    
      text("Scroll View Demo showing now "+curr, width>>1, thumbNailSize);
      text("Size of selected on left "+(basicImageSize*(curr+1))+"x900", width>>1, thumbNailSize*3);
    }
    
    void mouseReleased() {
    
      //if (mouseY>height>>2)    return;
    
      curr=(curr+1)%3;
    
      background(88);
    
      fill(255);
      noStroke();
      rect(0.80*thumbNailSize, thumbNailSize*0.80+thumbNailSize*5*curr, thumbNailSize*4.5, thumbNailSize*4.5);
    
      image(img1, thumbNailSize, thumbNailSize, thumbNailSize*4, thumbNailSize*4);
      image(img2, thumbNailSize, thumbNailSize*6, thumbNailSize*4, thumbNailSize*4);
      image(img3, thumbNailSize, thumbNailSize*11, thumbNailSize*4, thumbNailSize*4);
    
    
    
      act.runOnUiThread(new Runnable() {
        @ Override
          public void run() {
    
          ImageView imgv1= (ImageView)  act.findViewById(imageID1); 
          ImageView imgv2= (ImageView)  act.findViewById(imageID2); 
          ImageView imgv3= (ImageView)  act.findViewById(imageID3); 
    
    
          if (curr==0) {
            imgv1.setImageBitmap((Bitmap)img1.getNative()); 
            imgv2.setImageBitmap((Bitmap)img2.getNative()); 
            imgv3.setImageBitmap((Bitmap)img3.getNative());
          } else if (curr==1) {          
            imgv1.setImageBitmap((Bitmap)img2.getNative()); 
            imgv2.setImageBitmap((Bitmap)img3.getNative()); 
            imgv3.setImageBitmap((Bitmap)img1.getNative());
          } else if (curr==2) {          
            imgv1.setImageBitmap((Bitmap)img3.getNative());  
            imgv2.setImageBitmap((Bitmap)img1.getNative()); 
            imgv3.setImageBitmap((Bitmap)img2.getNative());
          }
        }
      }
      );
    }
    
    
    //===========================================================================
    // OTHER FUNCTIONS:
    
    PImage initImage(int w, int h, int mode) {
      PImage aimg =createImage(w, h, mode);
    
      int s=w*h;
      float lower=random(225);
      float delta=25;
      colorMode(HSB, 255);
    
      aimg.loadPixels();
      for (int i=0; i<s; i++)
        aimg.pixels[i]=color(int(lower+delta*i*1.0/s), 255, 255);//color(random(upper), random(50, 200), random(upper,255));
      aimg.updatePixels();
      return aimg;
    }
    
    
    
    //===========================================================================
    // ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:
    
    
    @Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      act = this.getActivity();
      mC= act.getApplicationContext();
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
    
      Button switchButton= new Button(act);
      switchButton.setLayoutParams(new RelativeLayout.LayoutParams(width>>2,150));
      switchButton.setTextSize(10);
      //switchButton.setTextColor(Color.rgb(220,220,220));
      switchButton.setText ("Show next");
      switchButton.setX(width*0.60);
      switchButton.setY(200);
      switchButton.setOnClickListener(new View.OnClickListener(){
        public void onClick(View V){
    
          mouseReleased();
    
        }
      });
    
      ImageView imgView1 = new ImageView(act);
      imgView1.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView1.setId(imageID1=imgView1.generateViewId());
    
    
      ImageView imgView2 = new ImageView(act);
      imgView2.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView2.setId(imageID2=imgView2.generateViewId());
    
    
      ImageView imgView3 = new ImageView(act);
      imgView3.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView3.setId(imageID3=imgView3.generateViewId());
    
    
      LinearLayout linLay=new LinearLayout(act);
      linLay.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); 
      linLay.setOrientation(LinearLayout.VERTICAL);  
      linLay.addView(imgView1);
      linLay.addView(imgView2);
      linLay.addView(imgView3);
    
      sv = new ScrollView(act);
      sv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,height));  //, LinearLayout.LayoutParams.WRAP_CONTENT)); // ,height-int(displayHeight/8.0)));  
      sv.setVerticalScrollBarEnabled(true);  
      sv.setY(int(displayHeight/8.0));  
      sv.addView(linLay);
    
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
      //                 @@@@@@@@@@@@@@@@@@@@@@@@@@@
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
    
      fl = (FrameLayout)act.findViewById(R.id.content);
      fl.addView(switchButton);
      fl.addView(sv);
    }
    
    //  @@@@@@@@@@@@
    @Override 
      public void onStart() {
      super.onStart();
    }
    
    //  @@@@@@@@@@@@
    @Override 
      public void onResume() {
      super.onResume();
    
      act = this.getActivity();
      mC= act.getApplicationContext();
    
    }
    
  • Showing Visualizations in Particular Positions in Android Studio

    I have found an answer to my questions.. Answer lie in setting a Static ID to my FrameLayouts and then losing the "SetContentView()" method..

    public class MainActivity extends AppCompatActivity {
    
        private PApplet sketch1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            FrameLayout frame1 = new FrameLayout(this);
            frame1.setId(R.id.FrameLayoutTwo);
    
            sketch1 = new sketchone();
            PFragment fragment1 = new PFragment(sketch1);
            fragment1.setView(frame1, this);
    
        }
    
  • Processing to Android visualization on Android

    I have found an answer to my questions.. Answer lie in setting a Static ID to my FrameLayouts and then losing the "SetContentView()" method..

    package com.example.gebruiker.myapplication;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.FrameLayout;
    import processing.android.PFragment;
    import processing.core.PApplet;
    
    public class MainActivity extends AppCompatActivity {
    
        private PApplet sketch1;
        private PApplet sketch2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            FrameLayout frame1 = new FrameLayout(this);
            frame1.setId(R.id.FrameLayoutTwo);
    
            FrameLayout frame2 = new FrameLayout(this);
            frame2.setId(R.id.FrameLayoutOne);
    
            sketch1 = new sketchone();
            PFragment fragment1 = new PFragment(sketch1);
            fragment1.setView(frame1, this);
    
            sketch2 = new second_sketch();
            PFragment fragment2 = new PFragment(sketch2);
            fragment2.setView(frame2, this);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
            if (sketch1 != null) {
                sketch1.onRequestPermissionsResult(
                        requestCode, permissions, grantResults);
            }
    
            if (sketch2 != null) {
                sketch2.onRequestPermissionsResult(
                        requestCode, permissions, grantResults);
            }
    
        }
    
        @Override
        public void onNewIntent(Intent intent) {
            if (sketch1 != null) {
                sketch1.onNewIntent(intent);
            }
    
            if (sketch2 != null) {
                sketch2.onNewIntent(intent);
            }
        }
    
  • Showing Visualizations in Particular Positions in Android Studio

    I am developing an Application in Android. For the visualization part, I am using Processing. Now I would like to show a number of visualization on one Android Activity.

    The standard code for one visualization is the following:

    public class MainActivity extends AppCompatActivity {
      private PApplet sketch;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(CompatUtils.getUniqueViewId());
        setContentView(frame, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                         ViewGroup.LayoutParams.MATCH_PARENT));
    
        sketch = new Sketch();
        PFragment fragment = new PFragment(sketch);
        fragment.setView(frame, this);
      }
    

    The code found on the "Processing for Android" website works for a single visualization. Now I would like to extend this to a number of visualizations each given a specific (x,y) position on the Activity Layout. Which methods allow me to do that?

    Can you point me in the right direction?

    Kind regards,

    Niels

  • Scrollable image with ScrollView

    Demo showing Scroll View in Action. Notice that mousePressed does not work on top of the Scroll View container. You will need to add a listener to it. For the time being, mousePressed only works on the top section of the demo. I have included a button for clarity. You get the Scroll view effect if the images(elements) you load there are larger than its defined height.

    Kf

    //===========================================================================
    // IMPORTS:
    
    import android.app.Activity;
    import android.content.Context;
    import android.widget.FrameLayout;
    //import android.app.Fragment;
    
    import android.os.Environment;
    import android.graphics.Color;
    import android.widget.Toast;
    import android.os.Looper;
    import android.view.WindowManager;
    import android.os.Bundle;
    import android.view.ViewParent;
    import android.view.ViewGroup;
    import android.view.View;
    import android.widget.RelativeLayout;
    import android.widget.LinearLayout;
    import android.view.LayoutInflater;
    import android.R.string;
    
    import android.R;
    import android.widget.ImageView;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.util.Log;
    import android.widget.ScrollView;
    import android.widget.Button;
    
    
    //===========================================================================
    // FINAL FIELDS:
    
    
    //===========================================================================
    // GLOBAL VARIABLES:
    
    Activity act;
    Context mC;
    
    FrameLayout fl;
    ScrollView sv;
    int imageID1=-1;
    int imageID2=-1;
    int imageID3=-1;
    
    PImage img1, img2, img3;
    int curr=-1;
    
    
    //===========================================================================
    // PROCESSING DEFAULT FUNCTIONS:
    
    void setup() {
      fullScreen();
      orientation(PORTRAIT);
      //orientation(LANDSCAPE;)
    
      act = this.getActivity();
      Looper.prepare();
    
      textAlign(CENTER, CENTER);
      //rectMode(CENTER);
    
      fill(255);
      strokeWeight(2);
      textSize(32);
    
    
    
      img1=initImage(300, 900, ARGB);//loadImage("pic40.jpg");
      img2=initImage(600, 900, ARGB); 
      img3=initImage(900, 900, ARGB);
    
      curr=0;
    }
    
    void draw() {
    
      text("Scroll View Demo showing now "+curr,width>>1,50);
      text("Size of selected on left "+(300*(curr+1))+"x900",width>>1,125);
    }
    
    void mouseReleased() {
    
      //if (mouseY>height>>2)    return;
    
      curr=(curr+1)%3;
    
      background(88);
    
      fill(255);
      noStroke();
      rect(40, 40+250*curr, 220, 220);
    
      image(img1, 50, 50, 200, 200);
      image(img2, 50, 300, 200, 200);
      image(img3, 50, 550, 200, 200);
    
    
    
      act.runOnUiThread(new Runnable() {
        @ Override
          public void run() {
    
          ImageView imgv1= (ImageView)  act.findViewById(imageID1); 
          ImageView imgv2= (ImageView)  act.findViewById(imageID2); 
          ImageView imgv3= (ImageView)  act.findViewById(imageID3); 
    
    
          if (curr==0) {
            imgv1.setImageBitmap((Bitmap)img1.getNative()); 
            imgv2.setImageBitmap((Bitmap)img2.getNative()); 
            imgv3.setImageBitmap((Bitmap)img3.getNative());
          } else if (curr==1) {          
            imgv1.setImageBitmap((Bitmap)img2.getNative()); 
            imgv2.setImageBitmap((Bitmap)img3.getNative()); 
            imgv3.setImageBitmap((Bitmap)img1.getNative());
          } else if (curr==2) {          
            imgv1.setImageBitmap((Bitmap)img3.getNative());  
            imgv2.setImageBitmap((Bitmap)img1.getNative()); 
            imgv3.setImageBitmap((Bitmap)img2.getNative());
          }
        }
      }
      );
    }
    
    
    //===========================================================================
    // OTHER FUNCTIONS:
    
    PImage initImage(int w, int h, int mode) {
      PImage aimg =createImage(w, h, mode);
    
      int s=w*h;
      float lower=random(225);
      float delta=25;
      colorMode(HSB,255);
    
      aimg.loadPixels();
      for (int i=0; i<s; i++)
        aimg.pixels[i]=color(int(lower+delta*i*1.0/s),255,255);//color(random(upper), random(50, 200), random(upper,255));
      aimg.updatePixels();
      return aimg;
    }
    
    
    
    //===========================================================================
    // ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:
    
    
    //  @@@@@@@@@@@@
    @Override 
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      act = this.getActivity();
      mC= act.getApplicationContext();
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
    
      Button switchButton= new Button(act);
      switchButton.setLayoutParams(new RelativeLayout.LayoutParams(width>>2,150));
      switchButton.setTextSize(10);
      //switchButton.setTextColor(Color.rgb(220,220,220));
      switchButton.setText ("Show next");
      switchButton.setX(width*0.60);
      switchButton.setY(200);
      switchButton.setOnClickListener(new View.OnClickListener(){
        public void onClick(View V){
    
          mouseReleased();
    
        }
      });
    
      ImageView imgView1 = new ImageView(act);
      imgView1.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView1.setId(imageID1=imgView1.generateViewId());
    
    
      ImageView imgView2 = new ImageView(act);
      imgView2.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView2.setId(imageID2=imgView2.generateViewId());
    
    
      ImageView imgView3 = new ImageView(act);
      imgView3.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
      imgView3.setId(imageID3=imgView3.generateViewId());
    
    
      LinearLayout linLay=new LinearLayout(act);
      linLay.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); 
      linLay.setOrientation(LinearLayout.VERTICAL);  
      linLay.addView(imgView1);
      linLay.addView(imgView2);
      linLay.addView(imgView3);
    
      sv = new ScrollView(act);
      sv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height-450));  
      sv.setVerticalScrollBarEnabled(true);  
      sv.setY(450);  
      sv.addView(linLay);
    
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
      //                 @@@@@@@@@@@@@@@@@@@@@@@@@@@
    
      // OOOOOOOOOOOOOOOO---------------------------OOOOOOOOOOOOOOOO
    
    
      fl = (FrameLayout)act.findViewById(R.id.content);
      fl.addView(switchButton);
      fl.addView(sv);
    }
    
  • Not working emulator

    Ok, thank you for answering the questions. This is how I installed the AM in Processing. I want to document it here and keep in mind these notes are from memory. Just to add, I run the emulator in Processing just now and it worked.

    I have a Win 10 machine and P3.3.6 and AM4.0.1. I installed the Android SDK by installing Android Studio and selecting to install the Android SDK as well. I made a note of the sdk folder selected in the installation. Then I started Android Studio, I go to its SDK manager and I make sure I have Android API 26 (I didn't check this step, but I think I also have 21, 22 and 24). After they are installed, I closed AS. Then I ran Processing, I installed the AM as described above. After AM is installed, I switched from java to Android Mode in the PDE. The first time it tells me it cannot find the Android SDK and it gives me two options: Locate SDK Path Manually or Download SDK Automatically. I chose the first one and I provided the path of my SDK manually.

    Then before I do anything else, I go to Android >> SDK updater and I make sure there are no updates pending.

    Then in the processing IDE, I use the template I provide at the end of this post for testing. Then I go to Sketch>>Run in Emulator. As you described, an emulator window is launched where a Google animation is played for 15 seconds before the screen goes black. After about 2 minutes (ahhh slow laptop) I get the emulator showing me what it looks like a phone: Android Emulator - processing-phine:5566. My sketch is launched there. I click on the window and I register the ellipses.

    As a side note, I cannot comment if downloading the Android SDK automatically works all the time. I tried this method long ago and it didn't work for me. I stick to this manner to install my Android SDK. From what I read, it seems that installing it this option, through the PDE, provides all the files you need to run AM in Processing. The reason I do it through Android Studio is because I am able to select and remove items in the SDK through their program. These options are simply not present in the SDK Updater in Processing.

    Kf

    //===========================================================================
    // IMPORTS:
    
    import android.app.Activity;
    import android.content.Context;
    import android.widget.FrameLayout;
    //import android.app.Fragment;
    
    import android.os.Environment;
    import android.graphics.Color;
    import android.widget.Toast;
    import android.os.Looper;
    import android.view.WindowManager;
    import android.os.Bundle;
    import android.view.ViewParent;
    import android.view.ViewGroup;
    import android.view.View;
    import android.widget.RelativeLayout;
    import android.view.LayoutInflater;
    import android.R.string;
    
    
    //===========================================================================
    // FINAL FIELDS:
    
    
    //===========================================================================
    // GLOBAL VARIABLES:
    
    Activity act;
    Context mC;
    
    //===========================================================================
    // PROCESSING DEFAULT FUNCTIONS:
    
    void setup(){
      //size(400,600);
      fullScreen();
      orientation(PORTRAIT);
      //orientation(LANDSCAPE;)
    
      act = this.getActivity();
      Looper.prepare();
    
      textAlign(CENTER,CENTER);
      rectMode(CENTER);
    
      fill(255);
      strokeWeight(2);
      textSize(32);
    
    
    }
    
    void draw(){
    
      //Erases everything in the sketch every two seconds approx.
      if(frameCount%120==0) 
         background(0);
    
    }
    
    void keyReleased(){
    
    }
    
    void mouseReleased(){
      fill(random(255));
      ellipse(mouseX,mouseY,50,50);
    
    }
    
    
    //===========================================================================
    // OTHER FUNCTIONS:
    
    
    
    //===========================================================================
    // ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:
    
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onStart() {
      super.onStart();
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onResume() {
      super.onResume();
    
      act = this.getActivity();
      mC= act.getApplicationContext();
    
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onPause() {
      super.onPause();
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onStop() {
      super.onStop();
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onDestroy() {
      super.onDestroy();
    }
    

    Keywords: kf_keyword Android_SDK Android_SDK_Install Android_Emulator

  • Processing to Android visualization on Android

    I have tried the following to load two Processing sketches underneath each other..

    Layout file: two FrameLayouts, each for one Processing Sketch..

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.gebruiker.myapplication.MainActivity">
    
        <FrameLayout
            android:id="@+id/FrameLayoutWeather"
            android:layout_width="327dp"
            android:layout_height="226dp"
            android:layout_marginBottom="16dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.512"
            app:layout_constraintStart_toStartOf="parent">
    
        </FrameLayout>
    
        <FrameLayout
            android:id="@+id/FrameLayoutSketch"
            android:layout_width="327dp"
            android:layout_height="214dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="16dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    
        </FrameLayout>
    
    </android.support.constraint.ConstraintLayout>
    

    And the MainActivity..

    public class MainActivity extends AppCompatActivity {
    
        private PApplet sketch;
        private PApplet secondsketch;
        FrameLayout frameLayout_weather;
        FrameLayout frameLayout_sketch;
    
        @ Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            frameLayout_sketch = findViewById(R.id.FrameLayoutSketch);
            frameLayout_weather = findViewById(R.id.FrameLayoutWeather);
    
            sketch = new weatherBrussels();
            PFragment fragment_sketch = new PFragment(sketch);
            fragment_sketch.setView(frameLayout_sketch, this);
    
            secondsketch = new second_sketch();
            PFragment fragment_weather = new PFragment(secondsketch);
            fragment_weather.setView(frameLayout_weather, this);
    
        }
    
        @ Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[],
                                               int[] grantResults) {
            if (sketch != null) {
                sketch.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
            if (secondsketch != null) {
                secondsketch.onRequestPermissionsResult(requestCode, permissions,grantResults);
            }
        }
    
        @ Override
        public void onNewIntent(Intent intent) {
            if (sketch != null) {
                sketch.onNewIntent(intent);
            }
            if (secondsketch!= null){
                secondsketch.onNewIntent(intent);
            }
        }
    }
    

    I do not get an error message, but the Android Studio Project does not work either.

    Any ideas?

  • Processing to Android visualization on Android

    I am running Processing Sketches on Android Studio. Did it through exporting the project from Processing to Android, checking all the libraries. Then started a new Android Project, added these libraries, and that's it.. Now the question is how to project them in a visually appealing way on the activity layout.. For instance, how can I control how big the area is a Processing Sketch is displayed on. Another question is how to load a number of Processing Sketches in different places on the Layout.

    Does anyone have experience on this, can share some code, point me to some sketches...?

    THANKS!!!!

    public class MainActivity extends AppCompatActivity {  
    
    private PApplet sketch;
    private PApplet secondsketch;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(CompatUtils.getUniqueViewId());
        setContentView(frame, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
    
    
        sketch = new weatherBrussels();
    
        PFragment fragment = new PFragment(sketch);
        fragment.setView(frame, this);
    }
    
    
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[],
                                           int[] grantResults) {
        if (sketch != null) {
            sketch.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
    
    
    public void onNewIntent(Intent intent) {
        if (sketch != null) {
            sketch.onNewIntent(intent);
        }
    }
    

    }

  • Running Processing Sketches on Android

    Great, this indeed works for most of the code..

    I follow the procedure explained on the website: http://android.processing.org/tutorials/android_studio/index.html

    My code to load the code "Sketch.class" is the following:

    public class MainActivity extends AppCompatActivity {
    
    private PApplet sketch;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(CompatUtils.getUniqueViewId());
        setContentView(frame, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    
        //PFragment is not included in the core library
        sketch = new Sketch();
        PFragment fragment = new PFragment(sketch);
        fragment.setView(frame,this);
    }
    
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (sketch != null){
            sketch.onRequestPermissionsResult(requestCode,permissions,grantResults);
        }
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        if (sketch != null){
            sketch.onNewIntent(intent);
        }
    }
    

    }

    Two errors here: - The "onRequestPermissionsResult" call requires API level 23, this would allow me to target only 40% of devices. Is there a way to circumvent this call and include more devices?

    • The "onNewIntent" call gives an error message "has protected access in Activity"

    Any ideas, suggestions?

    Thank you very much for your help..

  • Android Input Box

    Thank you very much for this -almost giving all answers to my questions- code. Sorry that I've still some questions. I do my research but english is not even my second language and I hope you'll bare with me. :) So you used fl = (FrameLayout)act.findViewById(R.id.content); That would make it work on almost every device/api? On what device/api did you tested the code? And then for the button you used instead of iButton = (iButton) findViewById,
    setId(MY_BUTTON1); But why is MY_BUTTON1 9000? I don"t understand the working of this yet. So now I take akenaton's second point. The button, of which you already kindly gave an example. For my one line purpose the code above is sufficient, but @akaneton is right because if I want to write a class for multiple boxes I'll need buttons. But rather then using a simple button I would like to have a custom button using widget's imageButton. My question would be: how link the image in the data folder programmatically rather than using a XML file? And than, in the code below I drew the design into an image() array How can I link this to the button? Notice I still used the findView but I would like to use the setId Thanks in advance.

    import android.content.Context;
    import android.content.Intent;
    import android.content.*;   //View;
    import android.widget.FrameLayout;
    import android.widget.RelativeLayout;
    import android.widget.LinearLayout;  
    import android.graphics.Color;
    import android.view.WindowManager;
    import android.view.inputmethod.InputMethodManager;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.ViewParent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup.LayoutParams;
    import android.view.Gravity;
    import android.R;
    import android.app.Activity; 
    import android.os.Bundle; 
    import android.widget.ImageButton; 
    
    PGraphics ib; 
    ImageButton myImageButton;
     int xbut, ybut, wbut = 110, hbut = 35;
    
    void setup() {
      fullScreen();
      orientation(LANDSCAPE);
      background(0, 0, 255);
      xbut = width/10;
      ybut = height/6;
      ib = createGraphics(wbut, hbut);
      drawib();
    }
    
    // image(ib, width/?, height/?);   //  How to link?
    
    void draw() {
    }
    
    @ Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    }
    
    @ Override 
      public void onStart() {
      super.onStart();
      act = this.getActivity();
      mC= act.getApplicationContext();
      act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
      myImageButton = new ImageButton(act);
      myImageButton.setX(xbut);
      myImageButton.setY(ybut);
      myImageButton.setHeight(hbut); 
      myImageButton.setWidth(wbut); 
      myImageButton.setId(MY_BUTTON1); // ??
      fl = (FrameLayout)act.findViewById(R.id.content);
      FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.LEFT);  
      fl.addView(myImageButton, params1);
    }
    
    @Override
      public void onCreate(Bundle savedInstanceState) {         
      super.onCreate(savedInstanceState);       
      setContentView(R.layout.main);        
      addListenerOnButton();
    }   
    
    void addListenerOnButton() {        
      myImageButton = (ImageButton) findViewById(    // <<<????  How to link to image()
      myImageButton.setOnClickListener(new OnClickListener() { 
     @Override  
        public void onClick(View arg0) {             
          println("clicked");
        }
      }
      );
    }
    
    void drawib() {
      ib.beginDraw(); 
      ib.textSize(20);
      ib.stroke(127);
      ib.rect (0, 0, ib.width, ib.height); );
      color c2 = color(130, 0, 0);
      color c1 = color(255, 85, 0);
      for (int i = 0; i <= ib.height; i++) { 
        float inter = map(i, 0, ib.height, 0, 1); 
        color c = lerpColor(c1, c2, inter); 
        ib.stroke(c); 
        ib.line(0, i, ib.width, i);
      }
      ib.fill(255);
      ib.text("Input", 30, 25);
      ib.endDraw();
    }
    
  • Android Input Box

    I am not sure if this answers all your questions bc I am not sure what is the current status of your code. This next is tested. Notice some added imports and a single line change in setup, between other minor changes, like adding a button from Android widgets.

    Kf

    //REFERENCE: https:// forum.processing.org/two/discussion/26349/android-input-box#latest
    //REFERENCE: https:// forum.processing.org/two/discussion/14206/on-screen-buttons-without-apwidgets
    //REFERENCE:
    //REFERENCE:
    //REFERENCE:
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.*;   //View;
    import android.widget.FrameLayout;
    import android.widget.RelativeLayout;
    import android.widget.LinearLayout;  
    import android.widget.EditText;
    import android.widget.TextView;
    import android.text.Editable;
    import android.graphics.Color;
    import android.view.WindowManager;
    import android.view.inputmethod.InputMethodManager;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.ViewParent;
    import android.view.View.OnKeyListener;
    import android.view.View;
    import android.view.KeyEvent;
    
    import android.widget.Button;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup.LayoutParams;
    import android.view.Gravity;
    import    android.R;
    import android.widget.Toast;
    import android.os.Looper;
    
    private static final int MY_BUTTON1 = 9000;
    
    Activity act;
    Context mC;
    
    FrameLayout fl;
    EditText edit;
    Button iButton;
    
    String txt;
    int xbut, ybut, wbut = 110, hbut = 35;
    
    boolean pressed;
    
    
    void setup() {
      fullScreen();
      orientation(LANDSCAPE);
      background(0, 0, 255);
      xbut = width/10;
      ybut = height/6;
      inputButton(xbut, ybut, wbut, hbut);
    
       Looper.prepare();
    }
    
    void draw() {
    }
    
    void showInputBox() {
      background(0, 0, 255);
      String txt = edit.getText().toString();
      edit.getText().clear();
      inputButton(xbut, ybut, wbut, hbut);  
      act.runOnUiThread(
        new Runnable() { 
        public void run() {
          edit.setVisibility(View.VISIBLE);
          edit.requestFocus();
        }
      }
      );
    }
    
    
    
    void hideInputBox() {
      background(0, 0, 255);
      inputButton(xbut, ybut, wbut, hbut); 
      String txt = edit.getText().toString();
      text("Your input was:  " + txt, width/3, height/12);
      act.runOnUiThread(
        new Runnable() {
        public void run() {
          edit.setVisibility(View.GONE);
        }
      }
      );
    }  
    
    
    void mousePressed() {
      if (mouseX >= xbut && mouseX <= xbut + wbut &&  mouseY >= ybut && mouseY <= ybut + hbut) { 
        showInputBox();
      }
    }
    
    void inputButton (int x, int y, float w, float h) {
      textSize(20);
      stroke(127);
      rect(x, y, w, h);
      color c2 = color(130, 0, 0);
      color c1 = color(255, 85, 0);
      for (int i = y; i <= y+h; i++) { 
        float inter = map(i, y, y+h, 0, 1); 
        color c = lerpColor(c1, c2, inter); 
        stroke(c); 
        line(x, i, x+w, i);
      }
      fill(255);
      text("Input", x + 30, y + 25);
    }
    
    
    
    //===========================================================================
    // ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:
    
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onStart() {
      super.onStart();
      act = this.getActivity();
      mC= act.getApplicationContext();
    
      act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
    
    
      iButton = new Button(act);
      iButton.setText("InputButton");
      iButton.setBackgroundColor(Color.GREEN);
      iButton.setId(MY_BUTTON1);
      OnClickListener oclMonBouton = new OnClickListener() {
        public void onClick(View v) {
          println("clicked");
          pressed = true;
        }
      };
      iButton.setOnClickListener(oclMonBouton);
    
      edit = new EditText(mC);
      edit.setLayoutParams (
        new RelativeLayout.LayoutParams (
        RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        );
      edit.setHint("Write Here!");
      edit.setTextColor(Color.rgb(0, 0, 0));
      edit.setHintTextColor(Color.rgb(170, 170, 170));  
      edit.setBackgroundColor(Color.WHITE);      // edit.getBackground().setAlpha(255);  
      edit.getLayoutParams().width=14*width/26;  
      edit.getLayoutParams().height=height/17; 
      edit.setX(width/3);
      edit.setY(height/6);
      edit.requestFocus();
      edit.setInputType(android.text.InputType.TYPE_CLASS_TEXT);  
      edit.setOnKeyListener(
        new View.OnKeyListener() {
        @ Override
          public boolean onKey(View v, int keyCode, KeyEvent event) {
          if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode()== KeyEvent.KEYCODE_ENTER) {
            InputMethodManager imm = (InputMethodManager)v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            hideInputBox();
            return true;
          }
          return false;
        }
      }
      );
    
      fl = (FrameLayout)act.findViewById(R.id.content);
      FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);  
      fl.addView(iButton, params1);
      fl.addView(edit);
    
    
      android.view.inputmethod.InputMethodManager imm = (android.view.inputmethod.InputMethodManager) getActivity().getSystemService(android.content.Context.INPUT_METHOD_SERVICE);
      imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onResume() {
      super.onResume();
      act = this.getActivity();
      mC= act.getApplicationContext();
      act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onPause() {
      super.onPause();
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onStop() {
      super.onStop();
    }
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onDestroy() {
      super.onDestroy();
    }
    
  • Connecting VR and Ketai Bluetooth in Android mode

    I managed to get vr and ketai bluetooth working by simply declaring the kt variable in setup().

    void setup() { fullScreen(STEREO); bt = new KetaiBluetooth(this); bt.start(); ... }

    I did not need the onCreate() and onActivityResult() routines.

    (Linux Mint 18.2; Processing 3.3.6; Android mode 4.0.1; Huawei P7, P9)

  • How to scan wifi networks

    Ok, so i know that this code is sloppy, but i came up with this

        import java.util.List;
        import android.content.Context;
        import android.net.wifi.WifiManager;
        import android.net.wifi.WifiConfiguration;
        import android.net.wifi.ScanResult;
        import android.net.wifi.WifiInfo;
        import android.net.wifi.WifiConfiguration.KeyMgmt;
        import android.app.Activity;
        import android.content.BroadcastReceiver;
        import android.content.Intent;
        import android.content.IntentFilter;
    
        Activity act;
        Context context;
        WifiManager wm;
        List<ScanResult> results;
        WifiInfo wifiInfo ;
    
        boolean primeraVez = true, segundo = false;
        List<ScanResult> result;
        WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); 
        BroadcastReceiver myDiscoverer = new myOwnBroadcastReceiver();
        IntentFilter IF = new IntentFilter(wifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    
        void setup()
        {
          fullScreen();
          act = this.getActivity();
          context = act.getApplicationContext();
          this.getActivity().registerReceiver(myDiscoverer, IF);
        } 
        void draw()
        {
          textSize(height/18);
          if (primeraVez)
          {
            primeraVez = false;
            wifiManager.startScan();
          }
          if(segundo)
          {
            println(result);
            segundo = false;
          }
        }
    
        public class myOwnBroadcastReceiver extends BroadcastReceiver {
        //<a href="/two/profile/Override">@Override</a>
            public void onReceive(Context context, Intent intent) {
            result = wifiManager.getScanResults();
            segundo = true;
          }
        }
    

    and when i try to run it the console throws the following "fatal exception"

        FATAL EXCEPTION: main
        Process: processing.test.sketch_180118a, PID: 23001
        java.lang.RuntimeException: Unable to start activity ComponentInfo{processing.test.sketch_180118a/processing.test.sketch_180118a.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2659)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
            at android.app.ActivityThread.-wrap12(ActivityThread.java)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:154)
            at android.app.ActivityThread.main(ActivityThread.java:6123)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
        Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
            at processing.test.sketch_180118a.sketch_180118a.<init>(sketch_180118a.java:51)
            at processing.test.sketch_180118a.MainActivity.onCreate(MainActivity.java:24)
            at android.app.Activity.performCreate(Activity.java:6672)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2612)
            ... 9 more
    

    i have no idea what went wrong

  • Android ketai Bluetooth read

    I know this is far too late but I will answer this for those who always search before making questions. The code below uses the Ketai library, which is kept updated. The part of the Processing sketch that treads the configuring and pairing I left out, because it can be done on the android configuring. Just pair your let ´s say, Arduino Bluetooth shield like HC-05 or whatever you named it. Change the "bt.connectToDeviceByName("HC-05");" line with "your name", and run the sketch.

    First the arduino part:

             #include <SoftwareSerial.h>
              SoftwareSerial mySerial(10,11);
    
             void setup() {
                mySerial.begin(9600);
             }
    
             void loop() {
                for (int i=-100; i<=100; i++){ 
                   String s = "^" + String(i);
                   mySerial.print(s);
                  //  String s = "^The quick brown fox jumped over the lazy dog.";
                  //  mySerial.write (32);
                  //  mySerial.write (65);
                  //  mySerial.write (64);
                    delay(300);
                }
             }
    

    The Processing code:

                import android.content.Intent;
                import android.os.Bundle;
                import ketai.net.bluetooth.*;
                import ketai.ui.*;
                import ketai.net.*;
    
                KetaiBluetooth bt;
                KetaiList klist;
                int val = 0;
                String stringInfo = "";
    
                void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  bt = new KetaiBluetooth(this);
                }
    
                void onActivityResult(int requestCode, int resultCode, Intent data) {
                  bt.onActivityResult(requestCode, resultCode, data);
                }
    
                void setup() {
                  fullScreen();
                  background(0);
                  fill(255);
                  textAlign(LEFT);
                  textSize(40);
                  bt.start();
                  bt.getPairedDeviceNames();
                  bt.connectToDeviceByName("HC-05");
                }
    
                void draw() {
                    background(0);
                    text(stringInfo , 20, 104);
                }
    
                void onBluetoothDataEvent(String who, byte[] data) {
                  if (data != null){
                    String str = new String(data);
                      if (str.charAt(0) != '^'){  // '^' = separator
                        stringInfo = str.substring(0, str.length());
                        val = Integer.valueOf(stringInfo);
                        println(val*2);
                      }
                   }
                }
    

    Large strings will be send in chunks of shorter data arrays so you have to put a delay in your ino file big enough to insure that the separator byte always be the end character in the data array, otherwise it will lose characters making it unreliable. For faster transfer, like file transfer you can copy the data arrays into a new array increasing the index number continuosly.

  • Connecting VR and Ketai Bluetooth in Android mode

    Hi all,

    I am having problems connecting VR mode and Ketai Bluetooth connectivity in Android mode. (Win10; Porcessing 3.3.5; Android 6.0.1; Samsung S5 Neo). Independently code for Ketai bluetooth works:

    import processing.vr.*;
    import android.content.Intent;
    import android.os.Bundle;
    import ketai.net.bluetooth.*;
    import ketai.ui.*;
    //import ketai.net.*;
    
    PFont fontMy;
    KetaiBluetooth bt;
    String info = "";
    
    //********************************************************************
    // The following code is required to enable bluetooth at startup.
    //********************************************************************
    
    void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     bt = new KetaiBluetooth(this);
     println("Creating KetaiBluetooth");
    }
    
    void onActivityResult(int requestCode, int resultCode, Intent data) {
     bt.onActivityResult(requestCode, resultCode, data);
    }
    
    //********************************************************************
    
    void setup() {
      //fullScreen(STEREO);
      size(displayWidth, displayHeight, P3D);  
      //start listening for BT connections and connect to a device.
      bt.start();
      bt.connectDevice("00:14:03:06:37:0E");      
      //font size
      fontMy = createFont("SansSerif", 40);
      textFont(fontMy);
    }
    
    void calculate() {
    }
    
    void draw() {
      background(150);  
      translate(width/2, height/2);
      noStroke();     
      // Green box, Y axis 
      pushMatrix();
      translate(0, 200, 0);
      fill(0, 255, 0);
      box(100);
      popMatrix();
      // text from Bluetooth
     // info = "abc\ndef"; //debugging
      text(info, 20, 104);
    }
    
    void onBluetoothDataEvent(String who, byte[] data) {
      //received
      info = new String(data);
    }
    

    Everything connects nicely to my HC-05 and gets the info, and prints it next to the green box. But then I decide to add VR functionality, and everything goes wrong. So I un-comment //fullScreen(STEREO); and comment
    size(displayWidth, displayHeight, P3D);, and change Android mode from "App" to "VR". The build is successful, but the app crashes and I get the following error:

    java.lang.NullPointerException: Attempt to invoke virtual method 'boolean ketai.net.bluetooth.KetaiBluetooth.start()' on a null object reference at processing.test.test2.test2.setup(test2.java:63) at processing.core.PApplet.handleDraw(Unknown Source) at processing.vr.PSurfaceVR$AndroidVRStereoRenderer.onDrawEye(Unknown Source) at com.google.vr.sdk.base.CardboardViewNativeImpl.nativeOnDrawFrame(Native Method) at com.google.vr.sdk.base.CardboardViewNativeImpl.access$2500(CardboardViewNativeImpl.java:53) at com.google.vr.sdk.base.CardboardViewNativeImpl$RendererHelper.onDrawFrame(CardboardViewNativeImpl.java:569) at com.google.vr.ndk.base.GvrSurfaceView$GLThread.guardedRun(GvrSurfaceView.java:1643) at com.google.vr.ndk.base.GvrSurfaceView$GLThread.run(GvrSurfaceView.java:1324) handleDraw() called before finishing

    The VR-code will work nicely, if I comment the bt.start();and bt.connectDevice("00:14:03:06:37:0E");

    Is it normal? Can Ketai work with In-built Processing Arduino VR Mode at all?

    Thanks!

  • App randomly crashes when phone comes back from IDLE

    This document will give you the background: https://developer.android.com/guide/components/activities/activity-lifecycle.html

    Check examples in the forum: https://forum.processing.org/two/search?Search=oncreate

    Depending on the resources you use, implementing life cycle could be straight forward or potentially not supported. However if you stick to Android tools and resources, you could get a potentially more stable app.

    Please note most of the examples in the forum are based on a previous Android mode. With the later Android mode ( >4.0) you might need to tweak the code to make it work.

    Kf

  • Output slider values from Android (using Controlp5 and Ketai libraries) to Arduino

    Ok I figured out how to approximate what I want. Ideally, I would still like to send a smooth range of values from my slider, but instead I am sending incremental values (integers). Here is the updated code. However, I would still welcome any comments if anyone has a better way for me to output these values in an analog fashion.

        import android.content.Intent;
        import android.os.Bundle;
        import ketai.net.bluetooth.*;
        import ketai.ui.*;
        import ketai.net.*;
        import controlP5.*;                                                  //KZ: slider
        import cc.arduino.*;                                                  //KZ: slider
    
        PFont fontMy;                                                        //declaring font
        boolean bReleased = true;                                           //no permament sending when finger lets off the button
        KetaiBluetooth bt;                                                  // Create object from BtSerial class
        boolean isConfiguring = true;
        String info = "";
        KetaiList klist;
        ArrayList devicesDiscovered = new ArrayList();                     //store in array the discovered device
        boolean rectOver = false;
        int rec = 0;
    
    
        ControlP5 controlP5;                                                //KZ: for the sliders
        Arduino arduino;                                                     //KZ: for the sliders
    
        int SERVO1_turns = 0; // 0-6                                         //KZ: slider 1
        int SERVO2_turns = 0; // 0-6                                        //KZ: slider 2
        int SERVO3_turns = 0; // 0-6                                          //KZ: slider 3
    
        // The following code is required to enable bluetooth at startup.
        void onCreate(Bundle savedInstanceState)
        {
        super.onCreate(savedInstanceState);
        bt = new KetaiBluetooth(this);                                    //create the BtSerial object that will handle the connection
        }
    
        void onActivityResult(int requestCode, int resultCode, Intent data)
         {
        bt.onActivityResult(requestCode, resultCode, data);                 //to show the discovered device
        }
    
        void setup()
        {
        size(displayWidth, displayHeight);                                 //size of the phone screen
        smooth();
        frameRate(10);                                                    //the frame rate of my screen
        orientation(PORTRAIT);                                            //vertical
        bt.start();                                                       //start listening for BT connections
        isConfiguring = true;                                             //at my phone start select device…
        fontMy = createFont("SansSerif", 30);                             //font size
        textFont(fontMy);
    
        controlP5 = new ControlP5(this);
         controlP5.addSlider("SERVO1_turns",0,6,SERVO1_turns,100,200,50,500);     //KZ: slider
         controlP5.addSlider("SERVO2_turns",0,6,SERVO2_turns,330,200,50,500);    //KZ: slider
         controlP5.addSlider("SERVO3_turns",0,6,SERVO3_turns,550,200,50,500);    //KZ: slider
        }
    
        void draw()
        {
        //at app start select device
        if (isConfiguring)
    
        {
        ArrayList names;
    
        //create the BtSerial object that will handle the connection
        //with the list of paired devices
        klist = new KetaiList(this, bt.getPairedDeviceNames());
    
        isConfiguring = false;                                             //stop selecting device
        }
    
        //else
        //{
        //color a = color(255,0,0);                                          //KZ: red- main axis
        //color b = color(255,0,0);                                          //KZ: red- main axis
        //color d = color(255,0,0);                                          //KZ: red- main axis
        //color i = color(95, 191, 187);                                     //KZ: aqua- background of dots???
    
        //update(mouseX, mouseY);                                             //update our finger point at where of the screen
        //background(95, 191, 187);                                            //background color
    
        //if
        //((mousePressed)&&(rectOver)&&(rec==2))  
        //{       d = color(10,237,26);                                       //KZ: changes d from red to green
        //}
        //else if ((mousePressed)&&(rectOver)&&(rec==3))
        //{       a = color(10,237,26);                                       //KZ: changes a from red to green
        //}
        //else if ((mousePressed)&&(rectOver)&&(rec==4))
        //{       b = color(10,237,26);                                       //KZ: changes a from red to green
        //}
    
            if ((SERVO1_turns == 0)) {                                                        // 
            byte[] data = {'a'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO1_turns == 1)) {                                                        // 
            byte[] data = {'b'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO1_turns == 2)) {                                                        // 
            byte[] data = {'c'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO1_turns == 3)) {                                                        // 
            byte[] data = {'d'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO1_turns == 4)) {                                                        // 
            byte[] data = {'e'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO1_turns == 5)) {                                                        // 
            byte[] data = {'f'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO1_turns == 6)) {                                                        // 
            byte[] data = {'g'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
    
            if ((SERVO2_turns == 0)) {                                                        // 
            byte[] data = {'h'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO2_turns == 1)) {                                                        // 
            byte[] data = {'i'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO2_turns == 2)) {                                                        // 
            byte[] data = {'j'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO2_turns == 3)) {                                                        // 
            byte[] data = {'k'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO2_turns == 4)) {                                                        // 
            byte[] data = {'l'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO2_turns == 5)) {                                                        // 
            byte[] data = {'m'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO2_turns == 6)) {                                                        // 
            byte[] data = {'n'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 0)) {                                                        // 
            byte[] data = {'o'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 1)) {                                                        // 
            byte[] data = {'p'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 2)) {                                                        // 
            byte[] data = {'q'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 3)) {                                                        // 
            byte[] data = {'r'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 4)) {                                                        // 
            byte[] data = {'s'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 5)) {                                                        // 
            byte[] data = {'t'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
            if ((SERVO3_turns == 6)) {                                                        // 
            byte[] data = {'u'};                                                             // send 'x' to arduino when we move the slider
            bt.broadcast(data);                                                              //send with bt
            bReleased = false;                                                               // send data for once until next time we click the button again
            }
    
          //fill(a);                                                                //fill each area of button with the color declared above
          //stroke(162); //the shape covered with a grey color line
          //triangle(350,600,450,550,350,500);                                      //draw the triangle with the coordinates   //KZ: FR
          //fill(b);
          //triangle(350,350,450,300,350,250);                                      //KZ: 2x. FL
          //fill(d);
          //triangle(150,250,50,300,150,350);                                      //KZ: 4x. BL 
        //}
    
        //to print received data and show on screen
        fill(255);
        noStroke();
        textAlign(LEFT);
        text(info, 20, 104);
        noFill();
        }
    
        //void update(int x, int y) {                                       //to control the flag when we click a button
        // if ( overRect(350, 500, 100, 100) ) {                            //x, y, width, height
         //   rectOver = true;                   
          //  rec = 3;                                                      //Confirmed: Front Right
          //}
          //else if
          //( overRect(350, 250, 100, 100) ) {                              //x, y, width, height
          //  rectOver = true;                   
           // rec = 4;                                                      //Confirmed: Front Left
         // }
        //  else if
         // ( overRect(50, 250, 100, 100) ) {                                //x, y, width, height
          //  rectOver = true;                   
          //      rec = 2;                                                  //Confirmed: Back Left
         // }
          //else
         // {
           // rectOver = false;                                             //nothing s touched on screen
          //}
        //}
        //boolean overRect(int x, int y, int width, int height)  {           //KZ: to scan what area is touched
        //  if (mouseX >= x && mouseX <= x+width &&
        //      mouseY >= y && mouseY <= y+height)                           //to see if the mouse cursor inside rect
          //{
         //   return true;
         // } else {
         //   return false;
         // }
        //}
    
        void onKetaiListSelection(KetaiList klist)
        {
        String selection = klist.getSelection();                                //select the device to connect
        bt.connectToDeviceByName(selection);                                    //connect to the device
        klist = null;                                                          //dispose of bluetooth list for now
        }
    
        //Call back method to manage data received
        void onBluetoothDataEvent(String who, byte[] data)
        {
        if (isConfiguring)
        return;
        //received
        info += new String(data);
        if(info.length() > 150)                                               //clean the words on screen if string to long
        info = "";
        }//END of Android processing coding
    
  • Exporting PDF using a timer in an animation

    I've managed to export a .tiff from a timer from this animation code below. But I cannot work out how to do the same with a PDF. I've looked up the PDF ref... any help with code appreciated. This uses the hype framework (http://www.hypeframework.org/)

    // sketch set up
    
    import hype.*;
    import hype.extended.layout.HGridLayout;
    import hype.extended.behavior.HTimer;
    
    
    int           myStageW         = 700;
    int           myStageH         = 700;
    
    color         clrBG            = #FF3300;
    
    String        pathDATA         = "../../data/";
    
    // ************************************************************************************************************
    
    // sound set up
    
    import ddf.minim.*;
    import ddf.minim.analysis.*;
    
    Minim           minim;
    AudioInput      myAudio; // to get the audio input - either a line in or a mic etc
    //AudioPlayer       myAudio; // this one is to get audio in through the mp3...
    FFT             myAudioFFT;
    
    boolean         showVisualizer      = false;    
    
    int             myAudioRange        = 11;
    int             myAudioMax          = 100;
    
    float           myAudioAmp          = 40.0;
    float           myAudioIndex        = 0.2;
    float           myAudioIndexAmp     = myAudioIndex;
    float           myAudioIndexStep    = 0.35;
    
    float[]         myAudioData         = new float[myAudioRange];
    
    // ************************************************************************************************************
    
    HDrawablePool   pool;
    int             poolCols            = 5;
    int             poolRows            = 5;
    int             poolDepth           = 5;
    
    //              picks are made from the ranIndex
    //                                      v bass (orange)             v snare (blue)
    color[]         palette             = { #000000, #666666, #666666,  #FFFFFF,   #666666, #666666, #666666, #666666, #666666, #666666, #666666 };
    
    int             rotateNumX          = 0;
    int             rotateNumY          = 0;
    int             rotateNumZ          = 0;
    
    // ************************************************************************************************************
    
    HTimer timer;
    
    // ************************************************************************************************************
    
    void settings() {
        size(myStageW,myStageH,P3D);
    }
    
    void setup() {
        H.init(this).background(clrBG).use3D(true).autoClear(true);
    
        minim   = new Minim(this);
        myAudio = minim.getLineIn(Minim.MONO);
    
        // myAudio = minim.loadFile(pathDATA + "HECQ_With_Angels_Trifonic_Remix.wav");
        // myAudio.loop();
    
        myAudioFFT = new FFT(myAudio.bufferSize(), myAudio.sampleRate()); // buffersize = 1024 (comes from the audio file id if not specified). samplerate = 44100.00 (again, from fileif not specified).
        myAudioFFT.linAverages(myAudioRange); // calculates the average by grouping the frequency bands 'lineraly'. (using 256 here from the 'myAudioRange').
        //myAudioFFT.window(FFT.GAUSS);
    
        pool = new HDrawablePool(poolCols*poolRows*poolDepth);
        pool.autoAddToStage()
            .add(new HSphere())
            .layout (new HGridLayout().startX(-300).startY(-300).startZ(-300).spacing(150, 150, 150).rows(poolRows).cols(poolCols))
            .onCreate ( 
                new HCallback() {
                    public void run(Object obj) {
                        int ranIndex = (int)random(myAudioRange);
    
                        HSphere d = (HSphere) obj;
                        d
                            .size(10)
                            .strokeWeight(0)
                            .noStroke()
                            .fill(palette[ranIndex], 225)
                            .anchorAt(H.CENTER)
                            .extras( new HBundle().num("i", ranIndex) )
                        ;
                    }
                }
            )
            .requestAll()
        ;
    
    // ************************************************************************************************************
    
    // Timer - prints a frame every second (numCycles is in there to stop it printing tonnes whilst testing)
    
        timer = new HTimer()
            .numCycles(10)
            .interval(1000)
            .callback(
                new HCallback() {
                    public void run(Object obj){
                        //Output
                        saveFrame("../frames/######.tif");
                    }
                }
    
            )
        ;
    
    }
    
    void draw() {
        myAudioFFT.forward(myAudio.mix);
        myAudioDataUpdate();
    
        lights();
        sphereDetail(20);
    
        // do the rotation in the push/pop matrix
    
        pushMatrix();
            translate(width/2, height/2, -900);
    
            rotateX( map(rotateNumX, 0, myAudioMax, -(TWO_PI / 20), TWO_PI / 20) );
            rotateY( map(rotateNumY, 0, myAudioMax, -(TWO_PI / 20), TWO_PI / 20) );
            rotateZ( map(rotateNumZ, 0, myAudioMax, -(TWO_PI / 20), TWO_PI / 20) ) ;
    
            int fftRotateX = (int)map(myAudioData[0], 0, myAudioMax, -1, 20); //contolled by [0] = bass
            int fftRotateY = (int)map(myAudioData[3], 0, myAudioMax, -1, 20); //contolled by [3] = snare
            int fftRotateZ = (int)map(myAudioData[5], 0, myAudioMax, 1, -20); //contolled by [5] = can choose random one here inc another snare/bass
    
            rotateNumX += fftRotateX;
            rotateNumY += fftRotateY;
            rotateNumZ += fftRotateZ;
    
            H.drawStage();
    
            // draw the translucent box
    
            //stroke(#333333); fill(#242424, 50); box(600); noStroke(); noFill();
    
        popMatrix();
    
        for (HDrawable d : pool) {
            HBundle tempExtra = d.extras();
            int i = (int)tempExtra.num("i");
    
            int fftSize;
            if (i==0)       fftSize = (int)map(myAudioData[i], 0, myAudioMax, -200, 350); // bass
            else if (i==3)  fftSize = (int)map(myAudioData[i], 0, myAudioMax, 50, 350); // snare
            else            fftSize = (int)map(myAudioData[i], 0, myAudioMax, 2, 150); // snare
    
            d.size(fftSize);
        }
    
        //CALL TO WIDGET SHOULD BE THE LAST ITEM IN THE DRAW() FUNCTION, SO IT APPEARS ABOVE ALL OTHER VISUAL ASSETS
        if (showVisualizer) myAudioDataWidget();
    }
    
    void myAudioDataUpdate() {
        for(int i = 0; i < myAudioRange; ++i) {
            float tempIndexAvg = (myAudioFFT.getAvg(i) * myAudioAmp) * myAudioIndexAmp;
            float tempIndexCon = constrain(tempIndexAvg, 0, myAudioMax);
            myAudioData[i] = tempIndexCon;
            myAudioIndexAmp += myAudioIndexStep;
        }
        myAudioIndexAmp = myAudioIndex;
    
    }
    
    // ************************************************************************************************************
    
    void myAudioDataWidget() {
        noLights();
        hint(DISABLE_DEPTH_TEST);
        noStroke(); fill(0, 200); rect(0, height-112, width, 102);
    
            for(int i = 0; i < myAudioRange; ++i) {
                fill(#CCCCCC);
                rect(10 + (i * 5), (height - myAudioData[i]) - 11, 4, myAudioData[i]);
            }
            hint(ENABLE_DEPTH_TEST);
    }
    
    // ************************************************************************************************************
    
    
    void stop(){
        myAudio.close();
        minim.stop();
        super.stop();
    }