BLITZ video short demonstration

Posted in Computers | No Comments »

I recently recorded a short video of BLITZ. It shows the capability of sending large annotation data over the P2P bluetooth network. As a side note: Currently I am working on thumbnail creation, detail views for annotations and annotation removal.

BLITZ is making progress

Posted in Computers | No Comments »

Recently I have been working on BLITZ network communication protocol. Now there is a basic support for all kinds of annotations. Image annotations are still kind of lazy, because the MTU on bluetooth networks is too low, so the images have to be small. Next on my TODO list is breaking images into multiple messages, so they can be of any size.

First join annotation exchanged of bluetooth in BLITZ

First join annotation exchanged of bluetooth in BLITZ

syncing time between mac and iPhone

Posted in Computers | No Comments »

I was pissed that my iPhone reminded me almost one minute later of events than my mac. Somehow the clocks of both devices got out of sync more and more! First using google didn’t bring any good results, so here is how I have done it:

  1. login on your jailbreaked iPhone (using the root account)
  2. open the system clock on your mac to see when time switches to a full minute
  3. use the UNIX date command as follows: date MMDDhhmmYY while MM = month 01-12; DD = day 01-31; hh = hour 00-24; mm = minute 00-59 and YY = year’s last two digits (date 0911230109 would set the date to 11th september 11:01pm of the year 2009)

This might probably help some other iPhone users! Apple should actually a sync option for time into iTunes! Dumb asses!

BLITZ goes BTME colloquium

Posted in Computers | No Comments »

I’ve been invited to hold a colloquium on BLITZ at the BTME group. BTME stands for business transactions in mobile environments. I will try to set up a site with some slides to present BLITZ to a wider audience. It will be available after I held the presentation on 11.11.2009 at the FH Köln Campus Gummersbach.

BLITZ

BLITZ

BLITZ goes on

Posted in Computers | No Comments »

I am doing great progress on my BLITZ project. While the work on the user interface is coming to an end, I can soon start with the persistence of data locally on the iPhone. At the moment I would go for CoreData since it seems to be easy to use. Later for protocol export an XML based format would be more appreciated!

Anyway: some picture showing all three kinds of annotations that have yet been implemented (text, image and participant action)

the current BLITZ iPhone client

the current BLITZ iPhone client

working on BLITZ

Posted in Uncategorized | No Comments »

Since the winter semester started, I am working on an unfinished university project, that I started last summer. BLITZ is about easily creating protocols of discussions in work environments. It uses multimedia to keep the additional workload as low as possible. By using the bluetooth interface multiple mobile devices can edit the group’s protocol by annotating the recorded audio stream with pictures, GPS locations, tags or generic events.

Today I got my provisioning profiles running, so there is a little tease for you :)

I am currently working on the view implementation, since the default apple components seem to not fit all my needs.

BLITZ in the springboard (yellow icon)

BLITZ in the springboard (yellow icon)

DFT part 2

Posted in Computers | No Comments »

I spent some time writing a GUI for the DFT implementation I posted a few hours ago. My GUI supports a spectrum and sonogram view. To switch them just uncomment the line in the DFTPanel class. You can also switch between logarithmic and non-logarithmic scaling of the axes. Download the full code and a sample audio file here!

Discrete Fourier Transformation in Java

Posted in Computers | No Comments »

I wrote a simple application to prepare my self for some upcoming exams: a DFT implementation in Java that reads content from a 16bit mono PCM encoded Wave file. If you are interested, you can add some cool GUI and sonogram rendering to my code base. Otherwise feel free to use it in any way. It surely isn’t the best performing code, but it will do its work for basic research.

You can use the DFT class to generate output of the frequency spectrum on the terminal/command line. Copy it to Excel, Numbers, OpenOffice to make a visualization of the spectrum. Here are some samples:

Main.java

public class Main {

public static void main(String[] args) {
if (args.length < 1) {
System.out.println("please pass a 16bit PCM encoded Wave file as the first parameter");
System.exit(-1);
}

System.out.println("reading data from file: " + args[0]);
WaveResource waveResource = new WaveResource();
waveResource.loadFromFile(args[0]);

DFT dft = new DFT();
dft.setSamplesResource(waveResource);
dft.setWindowLength(64);
dft.doIt();
}

}

DFT.java

public class DFT {
	private WaveResource waveResource;
	private float[] samples;
	private Complex[] coefficients;
	private int windowLength;
	private int numberOfFourierChannels;
	private float precision;
	private float fourierChannelWidth;

	public DFT() {
		System.out.println("Discrete Fourier Transformation created");
	}

	public void setSamplesResource(WaveResource wr) {
		if (wr != null) {
			waveResource = wr;
			samples = waveResource.getSamplesAsFloat();
		}
	}

	public void setWindowLength(int v) {
		if (v > 0) {
			windowLength = v;
			precision = waveResource.getSampleRate() / (float) windowLength;
			numberOfFourierChannels = (int) (waveResource.getSampleRate() / precision);
			fourierChannelWidth = waveResource.getSampleRate() / (float) numberOfFourierChannels;

			if (windowLength > samples.length) {
				System.out.println("not enough samples to measure so many channels");
			}
		}
	}

	public void doIt() {
		System.out.println("sampling rate: " + waveResource.getSampleRate());
		System.out.println("precision: " + precision);
		System.out.println("number of fourier channels: " + numberOfFourierChannels);
		System.out.println("fourier channel width: " + fourierChannelWidth);

		coefficients = new Complex[numberOfFourierChannels/2];

		for (int omega = 0; omega < numberOfFourierChannels/2; omega++) {
			Complex c = new Complex();
			for (int i = 0; i < windowLength; i++) {
				double phi = -2*Math.PI*omega*i/windowLength;
				Complex e = new Complex(Math.cos(phi), Math.sin(phi));
				c = c.add(e.mult(samples[i]));
			}
			coefficients[omega] = c.div(Math.sqrt(windowLength));
		}
	}

	public void printCoefficients() {
		for (int omega = 0; omega < numberOfFourierChannels/2; omega++) {
			System.out.println(coefficients[omega].length());
		}
	}
}

WaveResource.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class WaveResource {
	private String fileName;
	File file;
	FileInputStream fileInputStream;
	private int[] samples;

	private long chunkSize;
	private String format;
	private String subChunkID;
	private long subChunkSize;
	private int numberOfSamples;
	private int numberOfChannels;
	private long sampleRate;
	private long byteRate;
	private int bitsPerSample;
	private int blockAlign;
	private String subChunkID2;
	private long subChunkSize2;
	private int audioFormat;

	private int maxWord;
	private int minWord;

	public WaveResource() {
		System.out.println("WaveResource created");
	}

	public long getSampleRate() {
		return sampleRate;
	}

	private void setBitsPerSample (int v) {
		bitsPerSample = v;

		maxWord = 0x00000000;
		minWord = 0xFFFFFFFF;

		for (int i = 0; i < v-1; i++) {
			maxWord = maxWord << 1;
			maxWord = maxWord | 0x1;

			minWord = minWord << 1;
		}
	}

	private long bytesToUnsignedInt (byte[] b) {
		return ((long)
				(0xFF & b[3]) << 24 |
				(0xFF & b[2]) << 16 |
				(0xFF & b[1]) << 8 |
				(0xFF & b[0])) & 0xFFFFFFFFL;
	}

	private int bytesToUnsignedShort (byte[] b) {
		return ((int)
				(0xFF & b[1]) << 8 |
				(0xFF & b[0])) & 0xFFFFFFFF;
	}

	private void load() {
		try {
			fileInputStream = new FileInputStream(file);

			// Skipping "RIFF"
			fileInputStream.skip(4);

			byte[] chunkSizeBuffer = new byte[4];
			fileInputStream.read(chunkSizeBuffer, 0, 4);
			chunkSize = bytesToUnsignedInt(chunkSizeBuffer);
			chunkSizeBuffer = null;

			byte[] formatBuffer = new byte[4];
			fileInputStream.read(formatBuffer, 0, 4);
			format = new String(formatBuffer);
			formatBuffer = null;

			byte[] subChunkIDBuffer = new byte[4];
			fileInputStream.read(subChunkIDBuffer, 0, 4);
			subChunkID = new String(subChunkIDBuffer);
			subChunkIDBuffer = null;

			byte[] subChunkSizeBuffer = new byte[4];
			fileInputStream.read(subChunkSizeBuffer, 0, 4);
			subChunkSize = bytesToUnsignedInt(subChunkSizeBuffer);
			subChunkSizeBuffer = null;

			byte[] audioFormatBuffer = new byte[2];
			fileInputStream.read(audioFormatBuffer, 0, 2);
			audioFormat = bytesToUnsignedShort(audioFormatBuffer);
			audioFormatBuffer = null;

			byte[] numberOfChannelsBuffer = new byte[2];
			fileInputStream.read(numberOfChannelsBuffer, 0, 2);
			numberOfChannels = bytesToUnsignedShort(numberOfChannelsBuffer);
			numberOfChannelsBuffer = null;

			byte[] sampleRateBuffer = new byte[4];
			fileInputStream.read(sampleRateBuffer, 0, 4);
			sampleRate = bytesToUnsignedInt(sampleRateBuffer);
			sampleRateBuffer = null;

			byte[] byteRateBuffer = new byte[4];
			fileInputStream.read(byteRateBuffer, 0, 4);
			byteRate = bytesToUnsignedInt(byteRateBuffer);
			byteRateBuffer = null;

			byte[] blockAlignBuffer = new byte[2];
			fileInputStream.read(blockAlignBuffer, 0, 2);
			blockAlign = bytesToUnsignedShort(blockAlignBuffer);
			blockAlignBuffer = null;

			byte[] bitsPerSampleBuffer = new byte[2];
			fileInputStream.read(bitsPerSampleBuffer, 0, 2);
			setBitsPerSample(bytesToUnsignedShort(bitsPerSampleBuffer));
			bitsPerSampleBuffer = null;

			byte[] subChunkID2Buffer = new byte[4];
			fileInputStream.read(subChunkID2Buffer, 0, 4);
			subChunkID2 = new String(subChunkID2Buffer);
			subChunkID2Buffer = null;

			byte[] subChunkSize2Buffer = new byte[4];
			fileInputStream.read(subChunkSize2Buffer, 0, 4);
			subChunkSize2 = bytesToUnsignedInt(subChunkSize2Buffer);
			subChunkSize2Buffer = null;

			numberOfSamples = (int) 8 * (int)subChunkSize2 / (bitsPerSample * numberOfChannels);

			byte[] dataBuffer = new byte[(int) subChunkSize2];
			fileInputStream.read(dataBuffer, 0, (int) subChunkSize2);

			if(bitsPerSample != 16) {
				System.out.println("WaveLoader class currently only supports 16bit word length");
			} else {
				samples = new int[numberOfSamples];
				for (int i = 0; i < dataBuffer.length; i+=2) {
					int index = i/2;
					samples[index] = (0xFF & dataBuffer[i+1]) << 8 | (0xFF & dataBuffer[i]); 					if (samples[index] > maxWord) {
						samples[index] = samples[index] + 2 * minWord;
					}
				}
			}

			dataBuffer = null;

			fileInputStream.close();

			// printing some format information
			System.out.println("chunk size: " + chunkSize);
			System.out.println("audio format: " + format);
			System.out.println("subchunk id: " + subChunkID);
			System.out.println("subchunk size: " + subChunkSize);
			System.out.println("audio format: " + audioFormat);
			System.out.println("channels: " + numberOfChannels);
			System.out.println("sample rate: " + sampleRate);
			System.out.println("byte rate: " + byteRate);
			System.out.println("block align: " + blockAlign);
			System.out.println("bits per sample: " + bitsPerSample);
			System.out.println("subchunk id 2: " + subChunkID2);
			System.out.println("subchunk size 2: " + subChunkSize2);

			System.out.println("Wave file successfully loaded! YEAH!");

		} catch (FileNotFoundException e) {
			System.out.println("the file " + fileName + " does not exist in the file system");

			fileName = null;
			file = null;

			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("the file " + fileName + " could not be read");

			e.printStackTrace();
		}
	}

	public void loadFromFile(String name) {
		if(name != "" && name != null) {
			fileName = name;
			file = new File(fileName);

			this.load();
		}
	}

	public float[] getSamplesAsFloat() {
		float[] floatSamples = new float[numberOfSamples];

		for (int i = 0; i < numberOfSamples; i++) { 			if (samples[i] >= 0) {
				floatSamples[i] = samples[i] / (float)maxWord;
			} else {
				floatSamples[i] = -samples[i] / (float)minWord;
			}
		}

		return floatSamples;
	}
}

Complex.java

public class Complex {

	private final double r;
	private final double i;

	public Complex(double a, double b){
		r = a;
		i = b;
	}

	public Complex(){
		r = 0;
		i = 0;
	}

	public String toString(){
		return r+"(r) "+i+"(i)";
	}

	public Complex mult(double a){
		return new Complex(r*a, i*a);
	}

	public Complex mult(Complex c){
		return new Complex(r*c.r - i*c.i, i*c.r + r*c.i);
	}

	public Complex div(double a){
		return new Complex(r*(1.0d/a), i*(1.0d/a));
	}

	public Complex conjugate(){
		return new Complex(r, -i);
	}

	public Complex add(Complex c) {
		return new Complex(r+c.r, i+c.i);
	}

	public double length() {
		return Math.sqrt(i*i+r*r);
	}

	public Complex normalize() {
		return new Complex(r/length(), i/length());
	}

}

Have fun :)

First iPhone App online

Posted in Computers | No Comments »

Well, my first iPhone app made it into the iTunes store. For 0.79 Euro you can buy an animal photo book with sounds for each animal and some additional information. If you are curious, you can click on the link that brings up the iTunes store: BabyZoo Cologne

The following images are taken from the iTunes app site linked above:

BabyZoo Cologne start screen

BabyZoo Cologne start screen

BabyZoo Cologne

BabyZoo Cologne

dod_kolsch gallery

Posted in Games | No Comments »

I just wanted to post a few images of dod_kolsch since it was my last map I made for a game.