<commit_before>package com.haxademic.core.app;

import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;

import com.haxademic.core.audio.AudioInputWrapper;
import com.haxademic.core.audio.AudioInputWrapperMinim;
import com.haxademic.core.audio.WaveformData;
import com.haxademic.core.constants.AppSettings;
import com.haxademic.core.constants.PRenderers;
import com.haxademic.core.debug.DebugUtil;
import com.haxademic.core.debug.DebugView;
import com.haxademic.core.debug.Stats;
import com.haxademic.core.draw.context.DrawUtil;
import com.haxademic.core.draw.toxi.MeshPool;
import com.haxademic.core.file.FileUtil;
import com.haxademic.core.hardware.kinect.IKinectWrapper;
import com.haxademic.core.hardware.kinect.KinectWrapperV1;
import com.haxademic.core.hardware.kinect.KinectWrapperV2;
import com.haxademic.core.hardware.kinect.KinectWrapperV2Mac;
import com.haxademic.core.hardware.midi.MidiWrapper;
import com.haxademic.core.hardware.osc.OscWrapper;
import com.haxademic.core.hardware.webcam.WebCamWrapper;
import com.haxademic.core.render.GifRenderer;
import com.haxademic.core.render.ImageSequenceRenderer;
import com.haxademic.core.render.JoonsWrapper;
import com.haxademic.core.render.MIDISequenceRenderer;
import com.haxademic.core.render.Renderer;
import com.haxademic.core.system.AppUtil;
import com.haxademic.core.system.JavaInfo;
import com.haxademic.core.system.P5Properties;
import com.haxademic.core.system.SecondScreenViewer;
import com.haxademic.core.system.SystemUtil;

import de.voidplus.leapmotion.LeapMotion;
import krister.Ess.AudioInput;
import processing.core.PApplet;
import processing.video.Movie;
import themidibus.MidiBus;

/**
 * PAppletHax is a starting point for interactive visuals, giving you a unified
 * environment for both realtime and rendering modes. It loads several Java
 * libraries and wraps them up to play nicely with each other.
 *
 * @author cacheflowe
 *
 */

public class PAppletHax
extends PApplet
{
//	Simplest launch:
//	public static void main(String args[]) { PAppletHax.main(Thread.currentThread().getStackTrace()[1].getClassName()); }

//	Fancier launch:
//	public static void main(String args[]) {
//		PAppletHax.main(P.concat(args, new String[] { "--hide-stop", "--bgcolor=000000", Thread.currentThread().getStackTrace()[1].getClassName() }));
//		PApplet.main(new String[] { "--hide-stop", "--bgcolor=000000", "--location=1920,0", "--display=1", ElloMotion.class.getName() });
//	}
	
//	public static String arguments[];
//	public static void main(String args[]) {
//		arguments = args;
//		PAppletHax.main(Thread.currentThread().getStackTrace()[1].getClassName());
//	}


	/**
	 * Global/static ref to PApplet - any audio-reactive object should be passed this reference, or grabbed from this static ref.
	 */
	protected static PAppletHax p;

	/**
	 * Loads the project .properties file to configure several app properties externally.
	 */
	public P5Properties appConfig;

	/**
	 * Loads an app-specific project .properties file.
	 */
	protected String customPropsFile = null;
	
	/**
	 * The current rendering engine
	 */
	protected String renderer;

	/**
	 * Single instance and wrapper for the ESS audio object.
	 */
	public AudioInputWrapper _audioInput;
	public AudioInputWrapperMinim audioIn;

	/**
	 * Single instance of the data needed to draw a realtime waveform / oscilloscpe.
	 */
	public WaveformData _waveformData;
	public WaveformData _waveformDataMinim;

	/**
	 * Renderer object for saving frames and rendering movies & gifs.
	 */
	public Renderer _renderer;
	public MIDISequenceRenderer _midiRenderer;
	public GifRenderer _gifRenderer;
	public ImageSequenceRenderer imageSequenceRenderer;

	/**
	 * Wraps up MIDI functionality with theMIDIbus library.
	 */
	public MidiWrapper midi = null;
	protected MidiBus midiBus;
	protected boolean _debugMidi = false;

	/**
	 * Loads and stores a pool of WETriangleMesh objects.
	 */
	public MeshPool meshPool = null;

	/**
	 * Wraps up Kinect functionality.
	 */
	public IKinectWrapper kinectWrapper = null;

	/**
	 * Wraps up Leap Motion functionality.
	 */
	public LeapMotion leapMotion = null;

	/**
	 * Wraps up incoming OSC commands with the oscP5 library.
	 */
	public OscWrapper _oscWrapper = null;

	/**
	 * Native Java object that simulates occasional keystrokes to prevent the system's screensaver from starting.
	 */
	protected Robot _robot;

	/**
	 * Executable's target frames per second.
	 * This value is set in .properties file.
	 */
	public int _fps;

	/**
	 * Stats debug class
	 */
	public Stats _stats;

	/**
	 * Flag for showing stats
	 */
	public boolean showDebug = false;

	/**
	 * Text for showing stats
	 */
	public DebugView debugView;
	public SecondScreenViewer appViewerWindow;

	/**
	 * Graphical render mode
	 */
	public String rendererMode;

	/**
	 * Joons renderer wrapper
	 */
	protected JoonsWrapper joons;

	/**
	 * Helps the Renderer object work with minimal reconfiguration. Maybe this should be moved at some point...
	 */
	protected Boolean _isRendering = true;
//	protected int _renderShutdown = -1;

	/**
	 * Helps the Renderer object work without trying to read an audio file
	 */
	protected Boolean _isRenderingAudio = true;

	/**
	 * Helps the Renderer object work without trying to read a MIDI file
	 */
	protected Boolean _isRenderingMidi = true;

	public void settings() {
		P.p = p = this;
		AppUtil.setFrameBackground(p,0,0,0);
		loadAppConfig();
		overridePropsFile();
		setRenderer();
		setSmoothing();
		setRetinaScreen();
	}
	
	/**
	 * Called by PApplet to run before the first draw() command.
	 */
	public void setup () {
		if(customPropsFile != null) DebugUtil.printErr("Make sure to load custom .properties files in settings()");
		p.rendererMode = p.g.getClass().getName();
		setAppletProps();
		checkScreenManualPosition();
		if(renderer != PRenderers.PDF) debugView = new DebugView( p );
		_stats = new Stats( p );
	}
	
	protected void loadAppConfig() {
		p.appConfig = new P5Properties(p);
		appConfig = p.appConfig;
		if( customPropsFile != null ) p.appConfig.loadPropertiesFile( customPropsFile );
		customPropsFile = null;
	}
	
	protected void setRetinaScreen() {
		if(p.appConfig.getBoolean(AppSettings.RETINA, false) == true) {
			if(p.displayDensity() == 2) {
				pixelDensity(2);
			} else {
				DebugUtil.printErr("Error: Attempting to set retina drawing on a non-retina screen");
			}
		}	
	}
	
	protected void setSmoothing() {
		if(p.appConfig.getInt(AppSettings.SMOOTHING, AppSettings.SMOOTH_HIGH) == 0) {
			p.noSmooth();
		} else {
			p.smooth(p.appConfig.getInt(AppSettings.SMOOTHING, AppSettings.SMOOTH_HIGH));	
		}
	}
	
	protected void setRenderer() {
		renderer = p.appConfig.getString(AppSettings.RENDERER, P.P3D);
		if(p.appConfig.getBoolean(AppSettings.SPAN_SCREENS, false) == true) {
			// run fullscreen across all screens
			p.fullScreen(renderer, P.SPAN);
		} else if(p.appConfig.getBoolean(AppSettings.FULLSCREEN, false) == true) {
			// run fullscreen - default to screen #1 unless another is specified
			p.fullScreen(renderer, p.appConfig.getInt(AppSettings.FULLSCREEN_SCREEN_NUMBER, 1));
		} else if(p.appConfig.getBoolean(AppSettings.FILLS_SCREEN, false) == true) {
			// fills the screen, but not fullscreen
			p.size(displayWidth,displayHeight,renderer);
		} else {
			if(renderer == PRenderers.PDF) {
				// set headless pdf output file
				p.size(p.appConfig.getInt(AppSettings.WIDTH, 800),p.appConfig.getInt(AppSettings.HEIGHT, 600), renderer, p.appConfig.getString(AppSettings.PDF_RENDERER_OUTPUT_FILE, "output/output.pdf"));
			} else {
				// run normal P3D renderer
				p.size(p.appConfig.getInt(AppSettings.WIDTH, 800),p.appConfig.getInt(AppSettings.HEIGHT, 600), renderer);
			}
		}
	}

	protected void overridePropsFile() {
		if( customPropsFile == null ) P.println("YOU SHOULD OVERRIDE overridePropsFile()");
	}

	protected void drawApp() {
		P.println("YOU MUST OVERRIDE drawApp()");
	}

	public void handleInput( boolean isMidi ) {
//		p.println("YOU MUST OVERRIDE KEYPRESSED");
		if( isMidi == true ) {

		} else {
//			P.println("p.key = "+p.key);
			// audio gain
//			if ( p.key == '.' || _midi.midiPadIsOn( MidiWrapper.PAD_14 ) == 1 ) _audioInput.gainUp();
//			if ( p.key == ',' || _midi.midiPadIsOn( MidiWrapper.PAD_13 ) == 1 ) _audioInput.gainDown();
			if ( p.key == '.' && _audioInput != null ) _audioInput.gainUp();
			if ( p.key == ',' && _audioInput != null ) _audioInput.gainDown();
			if ( p.key == '.' && audioIn != null ) audioIn.gainUp();
			if ( p.key == ',' && audioIn != null ) audioIn.gainDown();
			
			if (p.key == '/') showDebug = !showDebug;
		}
	}

	/**
	 * Sets some initial Applet properties for OpenGL quality, FPS, and nocursor().
	 */
	protected void setAppletProps() {
		_isRendering = p.appConfig.getBoolean(AppSettings.RENDERING_MOVIE, false);
		if( _isRendering == true ) DebugUtil.printErr("When rendering, make sure to call super.keyPressed(); for esc key shutdown");
		_isRenderingAudio = p.appConfig.getBoolean(AppSettings.RENDER_AUDIO, false);
		_isRenderingMidi = p.appConfig.getBoolean(AppSettings.RENDER_MIDI, false);
		_fps = p.appConfig.getInt(AppSettings.FPS, 60);
		p.showDebug = p.appConfig.getBoolean(AppSettings.SHOW_DEBUG, false);
		if(p.appConfig.getInt(AppSettings.FPS, 60) != 60) frameRate(_fps);
		if(p.appConfig.getBoolean(AppSettings.HIDE_CURSOR, false) == true ) p.noCursor();
	}
	
	protected void checkScreenManualPosition() {
		boolean isFullscreen = p.appConfig.getBoolean(AppSettings.FULLSCREEN, false);
		// check for additional screen_x params to manually place the screen
		if(p.appConfig.getInt("screen_x", -1) != -1) {
			if(isFullscreen == false) {
				DebugUtil.printErr("Error: Manual screen positioning requires AppSettings.FULLSCREEN = true");
				return;
			}
			surface.setSize(p.appConfig.getInt(AppSettings.WIDTH, 800), p.appConfig.getInt(AppSettings.HEIGHT, 600));
			surface.setLocation(p.appConfig.getInt("screen_x", 0), p.appConfig.getInt("screen_y", 0));  // location has to happen after size, to break it out of fullscreen
		}
		// check for always on top
		if(isFullscreen == true) {
			surface.setAlwaysOnTop(p.appConfig.getBoolean(AppSettings.ALWAYS_ON_TOP, true));
		}
	}

	/**
	 * Initializes app-wide support objects for hardware interaction and rendering purposes.
	 */
	protected void initHaxademicObjects() {
		// save single reference for other objects
		if( appConfig.getBoolean(AppSettings.INIT_ESS_AUDIO, true) == true ) {
			_audioInput = new AudioInputWrapper( p, _isRenderingAudio );
			_waveformData = new WaveformData( p, _audioInput.bufferSize() );
			if(appConfig.getBoolean(AppSettings.AUDIO_DEBUG, false) == true) JavaInfo.debugInfo();
		}
		if( appConfig.getBoolean(AppSettings.INIT_MINIM_AUDIO, true) == true ) {
			audioIn = new AudioInputWrapperMinim( p, _isRenderingAudio );
			_waveformDataMinim = new WaveformData( p, audioIn.bufferSize() );
		}
		_renderer = new Renderer( p, _fps, Renderer.OUTPUT_TYPE_MOVIE, p.appConfig.getString( "render_output_dir", FileUtil.getHaxademicOutputPath() ) );
		if(appConfig.getBoolean(AppSettings.RENDERING_GIF, false) == true) {
			_gifRenderer = new GifRenderer(appConfig.getInt(AppSettings.RENDERING_GIF_FRAMERATE, 45), appConfig.getInt(AppSettings.RENDERING_GIF_QUALITY, 15));
		}
		if(appConfig.getBoolean(AppSettings.RENDERING_IMAGE_SEQUENCE, false) == true) {
			imageSequenceRenderer = new ImageSequenceRenderer();
		}
		
		if( p.appConfig.getBoolean( AppSettings.KINECT_V2_WIN_ACTIVE, false ) == true ) {
			kinectWrapper = new KinectWrapperV2( p, p.appConfig.getBoolean( "kinect_depth", true ), p.appConfig.getBoolean( "kinect_rgb", true ), p.appConfig.getBoolean( "kinect_depth_image", true ) );
		} else if( p.appConfig.getBoolean( AppSettings.KINECT_V2_MAC_ACTIVE, false ) == true ) {
			kinectWrapper = new KinectWrapperV2Mac( p, p.appConfig.getBoolean( "kinect_depth", true ), p.appConfig.getBoolean( "kinect_rgb", true ), p.appConfig.getBoolean( "kinect_depth_image", true ) );
		} else if( p.appConfig.getBoolean( AppSettings.KINECT_ACTIVE, false ) == true ) {
			kinectWrapper = new KinectWrapperV1( p, p.appConfig.getBoolean( "kinect_depth", true ), p.appConfig.getBoolean( "kinect_rgb", true ), p.appConfig.getBoolean( "kinect_depth_image", true ) );
		}
		if(kinectWrapper != null) {
			kinectWrapper.setMirror( p.appConfig.getBoolean( "kinect_mirrored", true ) );
			kinectWrapper.setFlipped( p.appConfig.getBoolean( "kinect_flipped", false ) );
		}
		if( p.appConfig.getInt(AppSettings.MIDI_DEVICE_IN_INDEX, -1) >= 0 ) {
			MidiBus.list(); // List all available Midi devices on STDOUT. This will show each device's index and name.
			midiBus = new MidiBus(
					this, 
					p.appConfig.getInt(AppSettings.MIDI_DEVICE_IN_INDEX, 0), 
					p.appConfig.getInt(AppSettings.MIDI_DEVICE_OUT_INDEX, 0)
					);
			_debugMidi = p.appConfig.getBoolean(AppSettings.MIDI_DEBUG, false);
		}
		if( p.appConfig.getBoolean( "leap_active", false ) == true ) leapMotion = new LeapMotion(this);
		if( p.appConfig.getBoolean( "osc_active", false ) == true ) _oscWrapper = new OscWrapper( p );
		meshPool = new MeshPool( p );
		joons = ( p.appConfig.getBoolean(AppSettings.SUNFLOW, false ) == true ) ?
				new JoonsWrapper( p, width, height, ( p.appConfig.getString(AppSettings.SUNFLOW_QUALITY, "low" ) == AppSettings.SUNFLOW_QUALITY_HIGH ) ? JoonsWrapper.QUALITY_HIGH : JoonsWrapper.QUALITY_LOW, ( p.appConfig.getBoolean(AppSettings.SUNFLOW_ACTIVE, true ) == true ) ? true : false )
				: null;
		try { _robot = new Robot(); } catch( Exception error ) { println("couldn't init Robot for screensaver disabling"); }
		if(p.appConfig.getBoolean(AppSettings.APP_VIEWER_WINDOW, false) == true) appViewerWindow = new SecondScreenViewer(p.g, p.appConfig.getFloat(AppSettings.APP_VIEWER_SCALE, 0.5f));
	}

	protected void initializeOn1stFrame() {
		if( p.frameCount == 1 ) {
			P.println("Using Java version: "+SystemUtil.getJavaVersion());
			initHaxademicObjects();
			if( p.appConfig.getString("midi_device_in", "") != "" ) {
				midi = new MidiWrapper( p, p.appConfig.getString("midi_device_in", ""), p.appConfig.getString("midi_device_out", "") );
			}
		}
	}
<commit_msg>Add setupFirstFrame() helper for overriding<commit_after>package com.haxademic.core.app;

import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;

import com.haxademic.core.audio.AudioInputWrapper;
import com.haxademic.core.audio.AudioInputWrapperMinim;
import com.haxademic.core.audio.WaveformData;
import com.haxademic.core.constants.AppSettings;
import com.haxademic.core.constants.PRenderers;
import com.haxademic.core.debug.DebugUtil;
import com.haxademic.core.debug.DebugView;
import com.haxademic.core.debug.Stats;
import com.haxademic.core.draw.context.DrawUtil;
import com.haxademic.core.draw.toxi.MeshPool;
import com.haxademic.core.file.FileUtil;
import com.haxademic.core.hardware.kinect.IKinectWrapper;
import com.haxademic.core.hardware.kinect.KinectWrapperV1;
import com.haxademic.core.hardware.kinect.KinectWrapperV2;
import com.haxademic.core.hardware.kinect.KinectWrapperV2Mac;
import com.haxademic.core.hardware.midi.MidiWrapper;
import com.haxademic.core.hardware.osc.OscWrapper;
import com.haxademic.core.hardware.webcam.WebCamWrapper;
import com.haxademic.core.render.GifRenderer;
import com.haxademic.core.render.ImageSequenceRenderer;
import com.haxademic.core.render.JoonsWrapper;
import com.haxademic.core.render.MIDISequenceRenderer;
import com.haxademic.core.render.Renderer;
import com.haxademic.core.system.AppUtil;
import com.haxademic.core.system.JavaInfo;
import com.haxademic.core.system.P5Properties;
import com.haxademic.core.system.SecondScreenViewer;
import com.haxademic.core.system.SystemUtil;

import de.voidplus.leapmotion.LeapMotion;
import krister.Ess.AudioInput;
import processing.core.PApplet;
import processing.video.Movie;
import themidibus.MidiBus;

/**
 * PAppletHax is a starting point for interactive visuals, giving you a unified
 * environment for both realtime and rendering modes. It loads several Java
 * libraries and wraps them up to play nicely with each other.
 *
 * @author cacheflowe
 *
 */

public class PAppletHax
extends PApplet
{
//	Simplest launch:
//	public static void main(String args[]) { PAppletHax.main(Thread.currentThread().getStackTrace()[1].getClassName()); }

//	Fancier launch:
//	public static void main(String args[]) {
//		PAppletHax.main(P.concat(args, new String[] { "--hide-stop", "--bgcolor=000000", Thread.currentThread().getStackTrace()[1].getClassName() }));
//		PApplet.main(new String[] { "--hide-stop", "--bgcolor=000000", "--location=1920,0", "--display=1", ElloMotion.class.getName() });
//	}
	
//	public static String arguments[];
//	public static void main(String args[]) {
//		arguments = args;
//		PAppletHax.main(Thread.currentThread().getStackTrace()[1].getClassName());
//	}


	/**
	 * Global/static ref to PApplet - any audio-reactive object should be passed this reference, or grabbed from this static ref.
	 */
	protected static PAppletHax p;

	/**
	 * Loads the project .properties file to configure several app properties externally.
	 */
	public P5Properties appConfig;

	/**
	 * Loads an app-specific project .properties file.
	 */
	protected String customPropsFile = null;
	
	/**
	 * The current rendering engine
	 */
	protected String renderer;

	/**
	 * Single instance and wrapper for the ESS audio object.
	 */
	public AudioInputWrapper _audioInput;
	public AudioInputWrapperMinim audioIn;

	/**
	 * Single instance of the data needed to draw a realtime waveform / oscilloscpe.
	 */
	public WaveformData _waveformData;
	public WaveformData _waveformDataMinim;

	/**
	 * Renderer object for saving frames and rendering movies & gifs.
	 */
	public Renderer _renderer;
	public MIDISequenceRenderer _midiRenderer;
	public GifRenderer _gifRenderer;
	public ImageSequenceRenderer imageSequenceRenderer;

	/**
	 * Wraps up MIDI functionality with theMIDIbus library.
	 */
	public MidiWrapper midi = null;
	protected MidiBus midiBus;
	protected boolean _debugMidi = false;

	/**
	 * Loads and stores a pool of WETriangleMesh objects.
	 */
	public MeshPool meshPool = null;

	/**
	 * Wraps up Kinect functionality.
	 */
	public IKinectWrapper kinectWrapper = null;

	/**
	 * Wraps up Leap Motion functionality.
	 */
	public LeapMotion leapMotion = null;

	/**
	 * Wraps up incoming OSC commands with the oscP5 library.
	 */
	public OscWrapper _oscWrapper = null;

	/**
	 * Native Java object that simulates occasional keystrokes to prevent the system's screensaver from starting.
	 */
	protected Robot _robot;

	/**
	 * Executable's target frames per second.
	 * This value is set in .properties file.
	 */
	public int _fps;

	/**
	 * Stats debug class
	 */
	public Stats _stats;

	/**
	 * Flag for showing stats
	 */
	public boolean showDebug = false;

	/**
	 * Text for showing stats
	 */
	public DebugView debugView;
	public SecondScreenViewer appViewerWindow;

	/**
	 * Graphical render mode
	 */
	public String rendererMode;

	/**
	 * Joons renderer wrapper
	 */
	protected JoonsWrapper joons;

	/**
	 * Helps the Renderer object work with minimal reconfiguration. Maybe this should be moved at some point...
	 */
	protected Boolean _isRendering = true;
//	protected int _renderShutdown = -1;

	/**
	 * Helps the Renderer object work without trying to read an audio file
	 */
	protected Boolean _isRenderingAudio = true;

	/**
	 * Helps the Renderer object work without trying to read a MIDI file
	 */
	protected Boolean _isRenderingMidi = true;

	public void settings() {
		P.p = p = this;
		AppUtil.setFrameBackground(p,0,0,0);
		loadAppConfig();
		overridePropsFile();
		setRenderer();
		setSmoothing();
		setRetinaScreen();
	}
	
	/**
	 * Called by PApplet to run before the first draw() command.
	 */
	public void setup () {
		if(customPropsFile != null) DebugUtil.printErr("Make sure to load custom .properties files in settings()");
		p.rendererMode = p.g.getClass().getName();
		setAppletProps();
		checkScreenManualPosition();
		if(renderer != PRenderers.PDF) debugView = new DebugView( p );
		_stats = new Stats( p );
	}
	
	protected void loadAppConfig() {
		p.appConfig = new P5Properties(p);
		appConfig = p.appConfig;
		if( customPropsFile != null ) p.appConfig.loadPropertiesFile( customPropsFile );
		customPropsFile = null;
	}
	
	protected void setRetinaScreen() {
		if(p.appConfig.getBoolean(AppSettings.RETINA, false) == true) {
			if(p.displayDensity() == 2) {
				pixelDensity(2);
			} else {
				DebugUtil.printErr("Error: Attempting to set retina drawing on a non-retina screen");
			}
		}	
	}
	
	protected void setSmoothing() {
		if(p.appConfig.getInt(AppSettings.SMOOTHING, AppSettings.SMOOTH_HIGH) == 0) {
			p.noSmooth();
		} else {
			p.smooth(p.appConfig.getInt(AppSettings.SMOOTHING, AppSettings.SMOOTH_HIGH));	
		}
	}
	
	protected void setRenderer() {
		renderer = p.appConfig.getString(AppSettings.RENDERER, P.P3D);
		if(p.appConfig.getBoolean(AppSettings.SPAN_SCREENS, false) == true) {
			// run fullscreen across all screens
			p.fullScreen(renderer, P.SPAN);
		} else if(p.appConfig.getBoolean(AppSettings.FULLSCREEN, false) == true) {
			// run fullscreen - default to screen #1 unless another is specified
			p.fullScreen(renderer, p.appConfig.getInt(AppSettings.FULLSCREEN_SCREEN_NUMBER, 1));
		} else if(p.appConfig.getBoolean(AppSettings.FILLS_SCREEN, false) == true) {
			// fills the screen, but not fullscreen
			p.size(displayWidth,displayHeight,renderer);
		} else {
			if(renderer == PRenderers.PDF) {
				// set headless pdf output file
				p.size(p.appConfig.getInt(AppSettings.WIDTH, 800),p.appConfig.getInt(AppSettings.HEIGHT, 600), renderer, p.appConfig.getString(AppSettings.PDF_RENDERER_OUTPUT_FILE, "output/output.pdf"));
			} else {
				// run normal P3D renderer
				p.size(p.appConfig.getInt(AppSettings.WIDTH, 800),p.appConfig.getInt(AppSettings.HEIGHT, 600), renderer);
			}
		}
	}

	protected void overridePropsFile() {
		if( customPropsFile == null ) P.println("YOU SHOULD OVERRIDE overridePropsFile(). Using run.properties");
	}

	protected void setupFirstFrame() {
		// YOU SHOULD OVERRIDE setupFirstFrame() to avoid 5000ms Processing/Java timeout in setup()
	}

	protected void drawApp() {
		P.println("YOU MUST OVERRIDE drawApp()");
	}
	
	public void handleInput( boolean isMidi ) {
//		p.println("YOU MUST OVERRIDE KEYPRESSED");
		if( isMidi == true ) {

		} else {
//			P.println("p.key = "+p.key);
			// audio gain
//			if ( p.key == '.' || _midi.midiPadIsOn( MidiWrapper.PAD_14 ) == 1 ) _audioInput.gainUp();
//			if ( p.key == ',' || _midi.midiPadIsOn( MidiWrapper.PAD_13 ) == 1 ) _audioInput.gainDown();
			if ( p.key == '.' && _audioInput != null ) _audioInput.gainUp();
			if ( p.key == ',' && _audioInput != null ) _audioInput.gainDown();
			if ( p.key == '.' && audioIn != null ) audioIn.gainUp();
			if ( p.key == ',' && audioIn != null ) audioIn.gainDown();
			
			if (p.key == '/') showDebug = !showDebug;
		}
	}

	/**
	 * Sets some initial Applet properties for OpenGL quality, FPS, and nocursor().
	 */
	protected void setAppletProps() {
		_isRendering = p.appConfig.getBoolean(AppSettings.RENDERING_MOVIE, false);
		if( _isRendering == true ) DebugUtil.printErr("When rendering, make sure to call super.keyPressed(); for esc key shutdown");
		_isRenderingAudio = p.appConfig.getBoolean(AppSettings.RENDER_AUDIO, false);
		_isRenderingMidi = p.appConfig.getBoolean(AppSettings.RENDER_MIDI, false);
		_fps = p.appConfig.getInt(AppSettings.FPS, 60);
		p.showDebug = p.appConfig.getBoolean(AppSettings.SHOW_DEBUG, false);
		if(p.appConfig.getInt(AppSettings.FPS, 60) != 60) frameRate(_fps);
		if(p.appConfig.getBoolean(AppSettings.HIDE_CURSOR, false) == true ) p.noCursor();
	}
	
	protected void checkScreenManualPosition() {
		boolean isFullscreen = p.appConfig.getBoolean(AppSettings.FULLSCREEN, false);
		// check for additional screen_x params to manually place the screen
		if(p.appConfig.getInt("screen_x", -1) != -1) {
			if(isFullscreen == false) {
				DebugUtil.printErr("Error: Manual screen positioning requires AppSettings.FULLSCREEN = true");
				return;
			}
			surface.setSize(p.appConfig.getInt(AppSettings.WIDTH, 800), p.appConfig.getInt(AppSettings.HEIGHT, 600));
			surface.setLocation(p.appConfig.getInt("screen_x", 0), p.appConfig.getInt("screen_y", 0));  // location has to happen after size, to break it out of fullscreen
		}
		// check for always on top
		if(isFullscreen == true) {
			surface.setAlwaysOnTop(p.appConfig.getBoolean(AppSettings.ALWAYS_ON_TOP, true));
		}
	}

	/**
	 * Initializes app-wide support objects for hardware interaction and rendering purposes.
	 */
	protected void initHaxademicObjects() {
		// save single reference for other objects
		if( appConfig.getBoolean(AppSettings.INIT_ESS_AUDIO, true) == true ) {
			_audioInput = new AudioInputWrapper( p, _isRenderingAudio );
			_waveformData = new WaveformData( p, _audioInput.bufferSize() );
			if(appConfig.getBoolean(AppSettings.AUDIO_DEBUG, false) == true) JavaInfo.debugInfo();
		}
		if( appConfig.getBoolean(AppSettings.INIT_MINIM_AUDIO, true) == true ) {
			audioIn = new AudioInputWrapperMinim( p, _isRenderingAudio );
			_waveformDataMinim = new WaveformData( p, audioIn.bufferSize() );
		}
		_renderer = new Renderer( p, _fps, Renderer.OUTPUT_TYPE_MOVIE, p.appConfig.getString( "render_output_dir", FileUtil.getHaxademicOutputPath() ) );
		if(appConfig.getBoolean(AppSettings.RENDERING_GIF, false) == true) {
			_gifRenderer = new GifRenderer(appConfig.getInt(AppSettings.RENDERING_GIF_FRAMERATE, 45), appConfig.getInt(AppSettings.RENDERING_GIF_QUALITY, 15));
		}
		if(appConfig.getBoolean(AppSettings.RENDERING_IMAGE_SEQUENCE, false) == true) {
			imageSequenceRenderer = new ImageSequenceRenderer();
		}
		
		if( p.appConfig.getBoolean( AppSettings.KINECT_V2_WIN_ACTIVE, false ) == true ) {
			kinectWrapper = new KinectWrapperV2( p, p.appConfig.getBoolean( "kinect_depth", true ), p.appConfig.getBoolean( "kinect_rgb", true ), p.appConfig.getBoolean( "kinect_depth_image", true ) );
		} else if( p.appConfig.getBoolean( AppSettings.KINECT_V2_MAC_ACTIVE, false ) == true ) {
			kinectWrapper = new KinectWrapperV2Mac( p, p.appConfig.getBoolean( "kinect_depth", true ), p.appConfig.getBoolean( "kinect_rgb", true ), p.appConfig.getBoolean( "kinect_depth_image", true ) );
		} else if( p.appConfig.getBoolean( AppSettings.KINECT_ACTIVE, false ) == true ) {
			kinectWrapper = new KinectWrapperV1( p, p.appConfig.getBoolean( "kinect_depth", true ), p.appConfig.getBoolean( "kinect_rgb", true ), p.appConfig.getBoolean( "kinect_depth_image", true ) );
		}
		if(kinectWrapper != null) {
			kinectWrapper.setMirror( p.appConfig.getBoolean( "kinect_mirrored", true ) );
			kinectWrapper.setFlipped( p.appConfig.getBoolean( "kinect_flipped", false ) );
		}
		if( p.appConfig.getInt(AppSettings.MIDI_DEVICE_IN_INDEX, -1) >= 0 ) {
			MidiBus.list(); // List all available Midi devices on STDOUT. This will show each device's index and name.
			midiBus = new MidiBus(
					this, 
					p.appConfig.getInt(AppSettings.MIDI_DEVICE_IN_INDEX, 0), 
					p.appConfig.getInt(AppSettings.MIDI_DEVICE_OUT_INDEX, 0)
					);
			_debugMidi = p.appConfig.getBoolean(AppSettings.MIDI_DEBUG, false);
		}
		if( p.appConfig.getBoolean( "leap_active", false ) == true ) leapMotion = new LeapMotion(this);
		if( p.appConfig.getBoolean( "osc_active", false ) == true ) _oscWrapper = new OscWrapper( p );
		meshPool = new MeshPool( p );
		joons = ( p.appConfig.getBoolean(AppSettings.SUNFLOW, false ) == true ) ?
				new JoonsWrapper( p, width, height, ( p.appConfig.getString(AppSettings.SUNFLOW_QUALITY, "low" ) == AppSettings.SUNFLOW_QUALITY_HIGH ) ? JoonsWrapper.QUALITY_HIGH : JoonsWrapper.QUALITY_LOW, ( p.appConfig.getBoolean(AppSettings.SUNFLOW_ACTIVE, true ) == true ) ? true : false )
				: null;
		try { _robot = new Robot(); } catch( Exception error ) { println("couldn't init Robot for screensaver disabling"); }
		if(p.appConfig.getBoolean(AppSettings.APP_VIEWER_WINDOW, false) == true) appViewerWindow = new SecondScreenViewer(p.g, p.appConfig.getFloat(AppSettings.APP_VIEWER_SCALE, 0.5f));
	}

	protected void initializeOn1stFrame() {
		if( p.frameCount == 1 ) {
			P.println("Using Java version: "+SystemUtil.getJavaVersion());
			initHaxademicObjects();
			if( p.appConfig.getString("midi_device_in", "") != "" ) {
				midi = new MidiWrapper( p, p.appConfig.getString("midi_device_in", ""), p.appConfig.getString("midi_device_out", "") );
			}
			setupFirstFrame();
		}
	}

{'fraction_non_alphanumeric': 0.12508288835375003, 'fraction_numerical': 0.006421666143161275, 'mean_word_length': 4.413565085962592, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1875716', 'n_tokens_mistral': 10385, 'n_tokens_neox': 9589, 'n_words': 2107}