public void run() {
		initJavaSound();
		sourceDataLine.start();
		// calibration test stuff
		long nanoStart = System.nanoTime();
		long nanoLeap = (long) (1000000000 / (audioFormat.getSampleRate() / (float) bufferSizeInFrames));
		boolean skipFrame = false;
		timeStep = 0;
		float[] interleavedOutput = new float[audioFormat.getChannels() * bufferSizeInFrames];
		while (root != null && !stop) {
			if (!skipFrame) {
				synchronized (this) {
					if (!root.isMuted())
						root.update(); // this will propagate most of the
										// updates
				}
				if (realTime) {
					interleave(root.bufOut, interleavedOutput);
					AudioUtils.floatToByte(bbuf, interleavedOutput,
							audioFormat.isBigEndian());
					sourceDataLine.write(bbuf, 0, bbuf.length);
				}
			}
			if (checkForDroppedFrames) {
				long expectedNanoTime = nanoLeap * (timeStep + 1);
				long realNanoTime = System.nanoTime() - nanoStart;
				float frameDifference = (float) (expectedNanoTime - realNanoTime)
						/ (float) nanoLeap;
				if (frameDifference < -1) {
					skipFrame = true;
					System.out.println("Audio dropped frame.");
				} else
					skipFrame = false;
			}
			timeStep++;
			if(logTime && timeStep % 100 == 0) {
				System.out.println(samplesToMs(timeStep * bufferSizeInFrames) / 1000f);
			}
		}
		sourceDataLine.stop();
		sourceDataLine.close();
	}