All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.refcodes.audio.AbstractLineOutSampleWriter Maven / Gradle / Ivy

Go to download

Artifact providing audio provessing functionality such as generating sine waves or writing raw audio samples to WAV files.

There is a newer version: 3.3.9
Show newest version
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.audio;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

/**
 * The {@link AbstractLineOutSampleWriter} provides a foundation means to write
 * sound samples to a line-out device.
 * 
 * @param  The {@link SoundSample} (sub-)type on which the
 *        {@link SampleWriter} implementation is to operate on.
 * @param  The {@link SampleWriter} implementing this
 *        {@link AbstractLineOutSampleWriter}.
 */
public abstract class AbstractLineOutSampleWriter> implements LineOutSampleWriter {

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	protected static final long MAX_16_BIT = 65535;
	protected static final long MAX_8_BIT = 255;

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	protected BitsPerSample _bitsPerSample = BitsPerSample.HIGH_RES;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Constructs an {@link AbstractLineOutSampleWriter}.
	 */
	public AbstractLineOutSampleWriter() {}

	/**
	 * Constructs an {@link AbstractLineOutSampleWriter} with the given
	 * {@link BitsPerSample} to use.
	 * 
	 * @param aBitsPerSample The bits/sample to use when doing audio playback.
	 */
	public AbstractLineOutSampleWriter( BitsPerSample aBitsPerSample ) {
		_bitsPerSample = aBitsPerSample;
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBitsPerSample( BitsPerSample aBitsPerSample ) {
		_bitsPerSample = aBitsPerSample;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public BitsPerSample getBitsPerSample() {
		return _bitsPerSample;
	}

	// /////////////////////////////////////////////////////////////////////////
	// HOOKS:
	// /////////////////////////////////////////////////////////////////////////

	protected long toWavSample( double eSampleData ) {
		return switch ( _bitsPerSample ) {
		case HIGH_RES -> (long) ( eSampleData * ( MAX_16_BIT / 2 ) ); // PCM SIGNED
		case LOW_RES -> (long) ( eSampleData * ( MAX_8_BIT / 2 ) ); // PCM SIGNED
		};
	}

	// /////////////////////////////////////////////////////////////////////////
	// HELPER:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Produces a line-out {@link SourceDataLine} instance for writing samples
	 * to.
	 * 
	 * @param aSoundSample The {@link SoundSample} from which to get the
	 *        according metrics.
	 * @param aBitsPerSample The preferred bits/sample.
	 * 
	 * @return An instance of the {@link SourceDataLine} to which to write data.
	 * 
	 * @throws LineUnavailableException thrown in case the audio-line cannot be
	 *         acquired.
	 */
	protected static SourceDataLine toLineOut( SoundSample aSoundSample, BitsPerSample aBitsPerSample ) throws LineUnavailableException {
		AudioSystem.getMixerInfo(); // Init the syound system...?!?
		// @formatter:off
		final AudioFormat format = new AudioFormat(
			AudioFormat.Encoding.PCM_SIGNED, // Encoding
			aSoundSample.getSamplingRate(), // Sample Rate
			aBitsPerSample.getBitCount() * aSoundSample.getChannelCount(), // Sample size in Bits 
			aSoundSample.getChannelCount(),  // Channels
			aBitsPerSample.getByteCount() * aSoundSample.getChannelCount(), //  Number of bytes in each frame
			aSoundSample.getSamplingRate(), // Number of frames per second
			true // True = big endian, false = little endian
		);
		// @formatter:on

		final DataLine.Info info = new DataLine.Info( SourceDataLine.class, format );
		final SourceDataLine theLine = (SourceDataLine) AudioSystem.getLine( info );
		theLine.open();
		theLine.start();
		return theLine;
	}
}