package soundtrack.optical; import processing.core.*; import processing.sound.*; public class SoundtrackOptical { String TYPE = "dual variable area"; int DPI = 2880; boolean POSITIVE = true; float VOLUME = (float) 1.0; String pitch = "long"; String FILEPATH; float IN = (float) 25.4; float FRAME_H = (float) 7.62; float FRAME_W = (float) (12.52 - 10.26); float DPMM = (float) (DPI / IN); int FRAME_H_PIXELS = (int) Math.round(DPMM * FRAME_H); int SAMPLE_RATE = FRAME_H_PIXELS * 24; int DEPTH = (int) Math.round(DPMM * FRAME_W); int RAW_RATE = 0; int RAW_FRAME_H = 0; int RAW_FRAME_W = 0; int LINE_W = 0; float DENSITY = 0; int LEFT = 0; int FRAMES = 0; int i = 0; float max = 0; float min = 0; float compare; float[] frameSample; SoundFile soundfile; PGraphics raw; PApplet parent; /** * @constructor * * * @param parent {PApplet} Parent process (usually this) * @param soundtrackFile {String} Path to soundtrackFile * @param dpi {Integer} Target DPI of printer * @param volume {Float} Volume of output soundtrack, 0 to 1.0 * @param type {String} Type of soundtrack either "unilateral", "variable area", "dual variable area", "multiple variable area", "variable density" * @param pitch {String} Pitch of the film, either "long" for projection or "short" for camera stock * @param positive {Boolean} Whether or not soundtrack is positive or negative */ @SuppressWarnings("static-access") public SoundtrackOptical (PApplet parent, String soundtrackFile, int dpi, float volume, String type, String pitch, boolean positive ) { this.parent = parent; FILEPATH = soundtrackFile; TYPE = type; DPI = dpi; VOLUME = volume; POSITIVE = positive; FRAME_H = (float) ((pitch == "long") ? 7.62 : 7.605); DPMM = DPI / IN; FRAME_H_PIXELS = (int) Math.round(DPMM * FRAME_H); SAMPLE_RATE = FRAME_H_PIXELS * 24; DEPTH = (int) Math.floor(DPMM * FRAME_W); soundfile = new SoundFile(parent, FILEPATH); RAW_RATE = soundfile.sampleRate(); RAW_FRAME_H = Math.round(RAW_RATE / 24); RAW_FRAME_W = Math.round(((RAW_RATE / 24) / FRAME_H ) * FRAME_W); FRAMES = (int) Math.ceil(soundfile.frames() / RAW_FRAME_H); frameSample = new float[RAW_FRAME_H]; raw = parent.createGraphics(RAW_FRAME_W, RAW_FRAME_H);//mode option? for (int x = 0; x < soundfile.frames(); x++) { compare = soundfile.read(x); if (compare > max) { max = compare; } if (compare < min) { min = compare; } } } public void draw (int X, int Y) { frame(X, Y, parent.frameCount); } @SuppressWarnings("static-access") public void frame(int X, int Y, int frameNumber) { if (frameNumber != -1) { i = frameNumber; } if (i >= FRAMES) { return; } raw.beginDraw(); //draw bg raw.noStroke(); if (POSITIVE) { raw.fill(0); } else { raw.fill(255); } if (TYPE != "variable density") { raw.rect(0, 0, RAW_FRAME_W, RAW_FRAME_H); } //draw top if (POSITIVE) { raw.stroke(255); } else { raw.stroke(0); } soundfile.read(i * RAW_FRAME_H, frameSample, 0, RAW_FRAME_H); for (int y = 0; y < RAW_FRAME_H; y++) { if (TYPE != "variable density") { LINE_W = Math.round(parent.map(frameSample[y], min, max, (float) 0, RAW_FRAME_W * VOLUME)); } if (TYPE == "unilateral") { unilateral(y, LINE_W); } else if (TYPE == "dual unilateral") { /* TODO!!!! */ } else if (TYPE == "single variable area" || TYPE == "variable area") { variableArea(y, LINE_W); } else if (TYPE == "dual variable area") { dualVariableArea(y, LINE_W); } else if (TYPE == "multiple variable area" || TYPE == "maurer") { multipleVariableArea(y, LINE_W); } else if (TYPE == "variable density") { variableDensity(y); } } raw.endDraw(); parent.image(raw, X, Y, DEPTH, FRAME_H_PIXELS); if (frameNumber == -1) { i++; } } private void unilateral (int y, int LINE_W) { raw.line(0, y, LINE_W, y); } private void variableArea (int y, int LINE_W) { LEFT = Math.round((RAW_FRAME_W - LINE_W) / 2); raw.line(LEFT, y, LEFT + LINE_W, y); } private void dualVariableArea (int y, int LINE_W) { LEFT = Math.round((RAW_FRAME_W / 4) - (LINE_W / 4)); raw.line(LEFT, y, LEFT + (LINE_W / 2), y); raw.line(LEFT + (RAW_FRAME_W / 2), y, LEFT + (RAW_FRAME_W / 2) + (LINE_W / 2), y); } private void multipleVariableArea (int y, int LINE_W) { LEFT = Math.round((RAW_FRAME_W / 16) - (LINE_W / 16)); for (int x = 1; x < 7; x++) { raw.line(LEFT + ((x * RAW_FRAME_W) / 8), y, LEFT + ((x * RAW_FRAME_W) / 8) + (LINE_W / 8), y); } } @SuppressWarnings("static-access") private void variableDensity(int y) { DENSITY = parent.map(frameSample[y], min, max, (float) 0, 255 * VOLUME); if (POSITIVE) { raw.stroke(DENSITY); } else { raw.stroke(255 - DENSITY); } raw.line(0, y, RAW_FRAME_W, y); } }