Soup - film development site

From Create52 Cookbook

Jump to: navigation, search

Source code for timer applet

Version 1.01:

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Quick film development timer using a bog standard Applet.
 * Version 1.01.
 * 
 * History:
 *  v1.00: initial release
 *  v1.01: moved timing logic and sound generation out of paint() method -
 *     sounds weren't being generated if applet wasn't visible (e.g. you
 *     were looking at another table in firefox, or minimised the browser)
 *  
 * @author Alex Hunsley Jan 2008
 *
 */

public class SoupTimer extends Applet {
	
	private static final String APPLET_PARAM_TIME = "time";

	private boolean loadingSounds = true;
	
	private static final String[] soundNames = {"tick.au", "a440.au", "a880alarm.au"};
	private static final int NUM_SOUNDS = soundNames.length;
	private static final int SOUND_TICK = 0;
	private static final int SOUND_BEEP = 1;
	private static final int SOUND_BEEP_ALARM = 2;
	
	private static final int MODE_WAITING_TO_START = 1;
	private static final int MODE_COUNTING_DOWN = 2;
	private static final int MODE_FINISHED_COUNTING_DOWN = 3;
	private static final int MODE_COUNTING_UP = 4;
	
	private int mode = MODE_WAITING_TO_START;
	
	private static final int PAINT_UPDATE_PERIOD = 100; //msecs
	
	private AudioClip[] clip = new AudioClip[NUM_SOUNDS];
	
	private static GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

	private static String[] fonts = ge.getAvailableFontFamilyNames();
	private int fontStyle = Font.PLAIN;
	
	private Font font = new Font("Helvetica", fontStyle, 72); 
	
	private long startTime = 0;
	private int minutes = 1;
	private int seconds = 30;
	private int totalSeconds = 0;
	private Timer timer;
	
	private String lastMsg = null;
	private String msg;
	
	private int AGITATE_EVERY = 60;
	private static final int NUM_BEEPS_WARNING = 4;
	
	private String timeParam = "";
	 
	public void init() {
		timeParam = getParameter(APPLET_PARAM_TIME);
		
		if (timeParam == null || timeParam.length() == 0 || timeParam.indexOf(':') < 0) {
			minutes = 4;
			seconds = 0;
			timeParam = "4:00";
		}
		else {
			StringTokenizer strTok = new StringTokenizer(timeParam, ":");
			String minsStr = strTok.nextToken();
			String secsStr = "0";
			if (strTok.hasMoreTokens()) {
				secsStr = strTok.nextToken();
			}
			
			minutes = Integer.parseInt(minsStr);
			seconds = Integer.parseInt(secsStr);
		}
		timer = new Timer();
		this.addMouseListener(clickyListen);
		totalSeconds = minutes * 60 + seconds;

		msg = secsToClock(totalSeconds);
		
		new Thread() {
			public void run() {
				for (int i=0; i < NUM_SOUNDS; i++) {
					clip[i] = getAudioClip(getCodeBase(), soundNames[i]);
				}		
			}
		}.start();
		
	}
	
	MouseAdapter clickyListen = new MouseAdapter() {
		public void mouseClicked(MouseEvent e) {
		
			if (mode == MODE_WAITING_TO_START) {
				mode = MODE_COUNTING_DOWN;
				startTime = System.currentTimeMillis();
				timer.schedule(tickTask,
	                     0, // delay
	                     PAINT_UPDATE_PERIOD); // period
				clip[SOUND_TICK].play();
			}
			else if (mode == MODE_FINISHED_COUNTING_DOWN) {
				mode = MODE_COUNTING_UP;
				startTime = System.currentTimeMillis();
				clip[SOUND_TICK].play();
			}
			repaint();
		}
	};
	
	public void stop() {
		if (tickTask != null) {
			tickTask.cancel();
		}
	}
	
	private static final String secsToClock(int totalSecs) {
		
		int secs = totalSecs % 60;
		int min = (totalSecs - secs) / 60;
		
		StringBuffer sBuff = new StringBuffer();
		if (min < 10) {
			sBuff.append("0");
		}
		sBuff.append(Integer.toString(min));
		sBuff.append(":");
		if (secs < 10) {
			sBuff.append("0");
		}
		sBuff.append(Integer.toString(secs));
		return sBuff.toString();
	}
	
	private TimerTask tickTask = new TimerTask() {
		public void run() {
			int elapsedSecs = 0;
			//if (mode != MODE_FINISHED_COUNTING_DOWN) {
				long currentTime = System.currentTimeMillis();
				elapsedSecs = (int)((currentTime - startTime) / 1000);
			
			if (mode == MODE_WAITING_TO_START) {
				elapsedSecs = 0;
			}
			
			//}
			//else {
			//	elapsedSecs = 0;
			//}
			int absSecs;
			
			if (mode != MODE_COUNTING_UP) {
				absSecs = totalSeconds - elapsedSecs;
			}
			else {
				absSecs = elapsedSecs;
			}

			int clockSecs = absSecs;
				
			if (absSecs == 0 && mode == MODE_COUNTING_DOWN) {
				mode = MODE_FINISHED_COUNTING_DOWN;
				//tickTask.cancel();
				playFinalAlarm();
			}

			
			if (clockSecs < 0) {
				clockSecs = 0;
			}
			msg = secsToClock(clockSecs);
			
			if (lastMsg == null) {
				lastMsg = msg;
			}
			
			if (! msg.equals(lastMsg)) {
				lastMsg = msg;
				if (mode != MODE_COUNTING_UP) {					
					int modSecs = elapsedSecs % AGITATE_EVERY;
		
					if (absSecs <= NUM_BEEPS_WARNING) {
						clip[SOUND_BEEP].play();
					}
					else if (modSecs == 0 || modSecs >= (AGITATE_EVERY - NUM_BEEPS_WARNING)) {
						clip[SOUND_TICK].play();
					}
								
				}
				repaint();
			}
			
		}
	};
	
	protected void playFinalAlarm() {
		new Thread() {
			public void run() {
				for (int i = 0; i < 10; i++) {
					clip[SOUND_BEEP_ALARM].play();
					try {
						sleep(500);
					}
					catch (Exception e) {
						// nowt
					}
				}
			}
		}.start();
	}
	
	public void paint(Graphics g) {
		if (msg == null) {
			return;
		}
		
		g.setColor(Color.black);
		g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
		g.drawRect(1, 1, getWidth() - 3, getHeight() - 3);
		
		//URL docBase = getCodeBase();
		if (mode == MODE_WAITING_TO_START) {
			g.drawString("Please click to start timer", 20, 20);
		}
		g.setFont(font);
		FontMetrics fm = g.getFontMetrics ();
		

	    int msg_width = fm.stringWidth (msg);

	    int ascent = fm.getMaxAscent ();
	    int descent= fm.getMaxDescent ();

	    int msg_x = getSize().width/2 - msg_width/2;
	    int msg_y = getSize().height/2 - descent/2 + ascent/2;

	    if (mode == MODE_FINISHED_COUNTING_DOWN) {
	    	g.setColor(Color.red);
	    }
	    else if (mode == MODE_COUNTING_UP) {
	    	g.setColor(Color.blue);
	    } else if (mode == MODE_WAITING_TO_START) {
	    	g.setColor(Color.gray);
	    }
	    g.drawString (msg, msg_x, msg_y);
	}
}

Version 1.0, daddy:

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Quick film development timer using a bog standard Applet.
 * Version 1.0.
 * 
 * @author Alex Hunsley Jan 2008
 *
 */

public class SoupTimer extends Applet {
	
	private static final String APPLET_PARAM_TIME = "time";

	private boolean loadingSounds = true;
	
	private static final String[] soundNames = {"tick.au", "a440.au", "a880alarm.au"};
	private static final int NUM_SOUNDS = soundNames.length;
	private static final int SOUND_TICK = 0;
	private static final int SOUND_BEEP = 1;
	private static final int SOUND_BEEP_ALARM = 2;
	
	private static final int MODE_WAITING_TO_START = 1;
	private static final int MODE_COUNTING_DOWN = 2;
	private static final int MODE_FINISHED_COUNTING_DOWN = 3;
	private static final int MODE_COUNTING_UP = 4;
	
	private int mode = MODE_WAITING_TO_START;
	
	private static final int PAINT_UPDATE_PERIOD = 100; //msecs
	
	private AudioClip[] clip = new AudioClip[NUM_SOUNDS];
	
	private static GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

	private static String[] fonts = ge.getAvailableFontFamilyNames();
	private int fontStyle = Font.PLAIN;
	
	private Font font = new Font("Helvetica", fontStyle, 72); 
	
	private long startTime = 0;
	private int minutes = 1;
	private int seconds = 30;
	private int totalSeconds = 0;
	private Timer timer;
	
	private String lastMsg = null;
	private int AGITATE_EVERY = 60;
	private static final int NUM_BEEPS_WARNING = 4;
	
	private String timeParam = "";
	 
	public void init() {
		timeParam = getParameter(APPLET_PARAM_TIME);
		
		if (timeParam == null || timeParam.length() == 0 || timeParam.indexOf(':') < 0) {
			minutes = 4;
			seconds = 0;
		}
		else {
			StringTokenizer strTok = new StringTokenizer(timeParam, ":");
			String minsStr = strTok.nextToken();
			String secsStr = "0";
			if (strTok.hasMoreTokens()) {
				secsStr = strTok.nextToken();
			}
			
			minutes = Integer.parseInt(minsStr);
			seconds = Integer.parseInt(secsStr);
		}
		timer = new Timer();
		this.addMouseListener(clickyListen);
		totalSeconds = minutes * 60 + seconds;
		
		new Thread() {
			public void run() {
				for (int i=0; i < NUM_SOUNDS; i++) {
					clip[i] = getAudioClip(getCodeBase(), soundNames[i]);
				}		
			}
		}.start();
		
	}
	
	MouseAdapter clickyListen = new MouseAdapter() {
		public void mouseClicked(MouseEvent e) {
		
			if (mode == MODE_WAITING_TO_START) {
				mode = MODE_COUNTING_DOWN;
				startTime = System.currentTimeMillis();
				timer.schedule(tickTask,
	                     0, // delay
	                     PAINT_UPDATE_PERIOD); // period
				clip[SOUND_TICK].play();
			}
			else if (mode == MODE_FINISHED_COUNTING_DOWN) {
				mode = MODE_COUNTING_UP;
				startTime = System.currentTimeMillis();
				clip[SOUND_TICK].play();
			}
			repaint();
		}
	};
	
	public void stop() {
		if (tickTask != null) {
			tickTask.cancel();
		}
	}
	
	private static final String secsToClock(int totalSecs) {
		
		int secs = totalSecs % 60;
		int min = (totalSecs - secs) / 60;
		
		StringBuffer sBuff = new StringBuffer();
		if (min < 10) {
			sBuff.append("0");
		}
		sBuff.append(Integer.toString(min));
		sBuff.append(":");
		if (secs < 10) {
			sBuff.append("0");
		}
		sBuff.append(Integer.toString(secs));
		return sBuff.toString();
	}
	
	private TimerTask tickTask = new TimerTask() {
		public void run() {
			repaint();
		}
	};
	
	protected void playFinalAlarm() {
		new Thread() {
			public void run() {
				for (int i = 0; i < 10; i++) {
					clip[SOUND_BEEP_ALARM].play();
					try {
						sleep(500);
					}
					catch (Exception e) {
						// nowt
					}
				}
			}
		}.start();
	}
	
	public void paint(Graphics g) {
		g.setColor(Color.black);
		g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
		g.drawRect(1, 1, getWidth() - 3, getHeight() - 3);
		
		//URL docBase = getCodeBase();
		if (mode == MODE_WAITING_TO_START) {
			g.drawString("Please click to start timer", 20, 20);
		}
		g.setFont(font);
		FontMetrics fm = g.getFontMetrics ();
		
		String msg = timeParam;
		
		int elapsedSecs = 0;
		
		//if (mode != MODE_FINISHED_COUNTING_DOWN) {
			long currentTime = System.currentTimeMillis();
			elapsedSecs = (int)((currentTime - startTime) / 1000);
		
		if (mode == MODE_WAITING_TO_START) {
			elapsedSecs = 0;
		}
		
		//}
		//else {
		//	elapsedSecs = 0;
		//}
		int absSecs;
		
		if (mode != MODE_COUNTING_UP) {
			absSecs = totalSeconds - elapsedSecs;
		}
		else {
			absSecs = elapsedSecs;
		}

		int clockSecs = absSecs;
			
		if (absSecs == 0 && mode == MODE_COUNTING_DOWN) {
			mode = MODE_FINISHED_COUNTING_DOWN;
			//tickTask.cancel();
			playFinalAlarm();
		}

		
		if (clockSecs < 0) {
			clockSecs = 0;
		}
		msg = secsToClock(clockSecs);
		
		if (lastMsg == null) {
			lastMsg = msg;
		}
		
		if (mode != MODE_COUNTING_UP) {
			if (! msg.equals(lastMsg)) {
				lastMsg = msg;
				int modSecs = elapsedSecs % AGITATE_EVERY;
	
				if (absSecs <= NUM_BEEPS_WARNING) {
					clip[SOUND_BEEP].play();
				}
				else if (modSecs == 0 || modSecs >= (AGITATE_EVERY - NUM_BEEPS_WARNING)) {
					clip[SOUND_TICK].play();
				}
							
			}
		}
		
	    int msg_width = fm.stringWidth (msg);

	    int ascent = fm.getMaxAscent ();
	    int descent= fm.getMaxDescent ();

	    int msg_x = getSize().width/2 - msg_width/2;
	    int msg_y = getSize().height/2 - descent/2 + ascent/2;

	    if (mode == MODE_FINISHED_COUNTING_DOWN) {
	    	g.setColor(Color.red);
	    }
	    else if (mode == MODE_COUNTING_UP) {
	    	g.setColor(Color.blue);
	    } else if (mode == MODE_WAITING_TO_START) {
	    	g.setColor(Color.gray);
	    }
	    g.drawString (msg, msg_x, msg_y);
	}
}

Database update 2008-01-07

Records 359-439 created in souptimes table as so:

,4,14,5,11,4:00,,0,1,0
,4,14,5,4,5:00,,0,1,0
,4,14,4,6,5:00,,0,1,0
,4,14,4,7,7:30,,0,1,0
,4,14,4,8,11:00,,0,1,0
,4,14,2,16,4:00,,0,1,0
,4,14,2,6,5:30,,0,1,0
,4,14,2,7,7:30,,0,1,0
,4,14,2,8,13:00,,0,1,0
,4,14,1,7,5:00,,0,1,0
,4,14,1,8,8:00,,0,1,0
,4,14,1,9,13:00,,0,1,0
,4,14,7,4,5:00,,0,1,0
,4,14,7,5,7:00,,0,1,0
,4,14,7,6,10:30,,0,1,0
,4,15,6,2,4:00,,0,1,0
,4,15,5,2,6:00,,0,1,0
,4,15,5,11,8:00,,0,1,0
,4,15,5,4,9:00,,0,1,0
,4,15,4,5,6:30,,0,1,0
,4,15,4,6,9:30,,0,1,0
,4,15,4,7,14:00,,0,1,0
,4,15,3,2,5:00,,0,1,0
,4,15,3,2,6:00,,0,1,0
,4,15,3,2,8:00,,0,1,0
,4,15,2,4,5:00,,0,1,0
,4,15,2,5,7:30,,0,1,0
,4,15,2,6,10:00,,0,1,0
,4,15,2,7,13:30,,0,1,0
,4,15,1,5,6:00,,0,1,0
,4,15,1,6,7:30,,0,1,0
,4,15,1,7,9:00,,0,1,0
,4,15,1,8,14:30,,0,1,0
,4,15,7,4,9:00,,0,1,0
,4,15,7,5,13:00,,0,1,0
,4,15,7,6,19:00,,0,1,0
,5,1,6,2,4:30,,0,1,0
,5,1,5,11,8:00,,0,1,0
,5,1,5,11,9:00,,0,1,0
,5,1,4,5,6:30,,0,1,0
,5,1,4,6,8:00,,0,1,0
,5,1,4,7,11:00,,0,1,0
,5,1,4,8,16:00,,0,1,0
,5,1,3,3,6:30,,0,1,0
,5,1,3,4,8:00,,0,1,0
,5,1,2,4,5:00,,0,1,0
,5,1,2,5,6:30,,0,1,0
,5,1,2,15,7:30,,0,1,0
,5,1,2,6,8:30,,0,1,0
,5,1,2,7,10:30,,0,1,0
,5,1,2,8,14:00,,0,1,0
,5,1,1,5,6:00,,0,1,0
,5,1,1,6,7:00,,0,1,0
,5,1,1,7,8:00,,0,1,0
,5,1,1,8,9:00,,0,1,0
,5,1,1,9,12:00,,0,1,0
,5,1,1,14,16:30,,0,1,0
,5,1,7,4,8:30,,0,1,0
,5,1,7,5,10:30,,0,1,0
,5,1,7,6,14:30,,0,1,0
,5,2,6,2,6:00,,0,1,0
,5,2,5,11,10:00,,0,1,0
,5,2,5,4,14:00,,0,1,0
,5,2,4,5,12:00,,0,1,0
,5,2,4,6,15:00,,0,1,0
,5,2,3,3,10:00,,0,1,0
,5,2,3,4,14:00,,0,1,0
,5,2,2,4,8:30,,0,1,0
,5,2,2,5,11:30,,0,1,0
,5,2,2,15,13:30,,0,1,0
,5,2,2,6,15:30,,0,1,0
,5,2,2,7,19:00,,0,1,0
,5,2,7,4,15:30,,0,1,0
,5,2,7,5,19:00,,0,1,0
,5,2,6,2,11:00,,0,1,0
,5,2,5,11,14:00,,0,1,0
,5,2,5,4,18:00,,0,1,0
,5,2,4,5,23:00,,0,1,0
,5,2,3,3,14:00,,0,1,0
,5,2,3,4,20:00,,0,1,0
,5,2,2,4,16:00,,0,1,0

This data was from the document linked to at http://www.ilfordphoto.com/applications/page.asp?n=87&t=Developing+Black+and+white+film (direct link to file: http://www.ilfordphoto.com/applications/download.asp?n=429)

The data imported was for developers HC and Microphen, all listed dilutions.

Personal tools