@Override
	public void start(AudioFormat playFormat) {
		try {
			/* Get the line to play from. */
			line = getLine(playFormat);
			if (line != null) {
				// Start the line
				line.start();
				
				// Figure out how big of an internal buffer the line has
				// We will read from the main buffer in chunks of this size
				int lineBufferSize = line.getBufferSize();
				
				// Spawn the event player thread to update the events every few ms
				new Thread(new Runnable() {

					@Override
					public void run() {
						playEvents();
					}
					
				}, "EventPlayerThread").start();
				
				// Start running and processing the buffer
				running.set(true);
				while(running.get()) {					
					// Lock the buffer and start playing it
					bufferLock.lock();
					try {
						// Wait until we have unprocessed data in the buffer
						while(bufferIsProcessed.get()) {
							bufferNotProcessed.await();
						}
						
						// Make sure the buffer is playable by the line
						if(!playFormat.toString().equals(soundBuffer.getFormat().toString())) {
							throw new IllegalArgumentException("buffer format does not match playing format");
						}
						
						// The initial chunk we put into the line should be the size
						// of the remaining chunk of data in the buffer. This allows
						// us to have the last chunk from the main buffer be the
						// full allowable size of the line buffer, which gives us
						// as much time as possible to copy the buffer from the Analyzer
						// into this Player.
						int chunkSize = soundBuffer.getNumBytesInBuffer() % lineBufferSize;
						int bytesWritten = 0;
						
						// Write bytes chunk by chunk into the line until we are out of buffer
						while (running.get() && bytesWritten < soundBuffer.getNumBytesInBuffer()) {
							/* 
							 * Write the buffer to the line and block until this is possible.
							 * We couldn't somehow, throw an IOException.
							 */
							int succededBytesWritten = line.write(soundBuffer.getBuffer(), bytesWritten, chunkSize);
							if(succededBytesWritten != chunkSize) {
								throw new IOException("never finished writing to the audio device!");
							}
							// Move along the buffer
							bytesWritten += succededBytesWritten;
							
							// Because we started by writing the odd block, the chunk size is always lineBufferSize
							chunkSize = lineBufferSize;
						}
						
						// Mark the buffer as processed
						bufferIsProcessed.set(true);
						bufferProcessed.signalAll();
					} finally {
						// Unlock the buffer so it can be loaded up again by the analyzer
						bufferLock.unlock();
					}
				}
				
				// Stop the line and close up shop
				line.drain();
				line.stop();
				line.close();
				line = null;
			}
		} catch(Exception e) {
			Log.get().warning("Exception\n", e);
		}
	}