Channels ▼
RSS

JVM Languages

Music Components in Java: The Synthesizer Core


Controlling Amplitude Dynamics

"Timbre" is the term that describes what gives musical instruments their distinct sounds. When you hear a guitar and a clarinet being played together, you typically have no problem deciding which instrument is which because the timbre of each is unique and vastly different. In real (non-virtual) instruments, timbre is influenced by the size of an instrument, the materials it is made from, its resonance characteristics, and how sound is generated. Picking a guitar string to produce sound is very different from blowing on a vibrating reed, for example.

The most important characteristics of timbre are the frequency spectrum (including the relative levels of all harmonics) produced by an instrument and its volume envelope. Frequency spectra will be discussed in the next section. I'll discuss volume envelopes here.

Every instrument has its own unique volume envelope. Some have short attack, decay, and release times while others might have medium attack time, short decay, medium sustain level and long release times. The beauty of coupling an EG to a variable gain element, as is done with a VCA, is it allows the generation of volume envelopes that mimic real instruments. It also has the ability to produce volume envelopes that do not occur naturally. And I should also mention that without a VCA in our typical signal path the sound of the oscillator would drone on forever.

With our understanding of amplitude modulation and the availability of the EG component we presented in the last article it is easy to build a digital VCA. Recall the output of our EG goes from 0.0 to 1.0 and back again using a timing profile established by the attack, decay, sustain, and release parameters set with its API. Figure 1 shows the phases of envelope generation.

Figure 1: Phases of envelope generation.

A single multiplication per sample is all that is required to control the amplitude of samples flowing through a VCA. Remembering the EG's getValue method returns its instantaneous output and that this method must be called every sample time, it is then a simple matter to multiply the EG's output with the sample value on a sample by sample basis. This arrangement means that samples are only passed unattenuated when the EG's value is equal to 1.0 and that sample values are attenuated during the remainder of the envelope. When the EG's output returns to 0.0 the value of samples passing through the VCA becomes 0.0, resulting in silence.

Implementation wise, the VCA class extends EnvelopeGenerator and implements SampleProviderIntfc. This arrangement allows the EG's APIs to be directly available to the user of the VCA class. The noteOn and noteOff methods form the control interface for the VCA.

Listing One: The VCA Class.

public class VCA extends EnvelopeGenerator implements SampleProviderIntfc {	
	/**
	 * VCA Class Constructor
	 * Creates an VCA instance and initializes it to default values
	 */
	public VCA() {
		
		// Set envelope generator to reasonable values
		setAttackTimeInMS(1);
		setDecayTimeInMS(1000);
		setSustainLevel(0.5);
		setReleaseTimeInMS(2000);
	}
	
	/**
	 * Setup the provider of samples
	 * @param provider The provider of samples for the VCA.
	 */
	public void setSampleProvider(SampleProviderIntfc provider) {
		this.provider = provider;
	}
		
	/**
	 * Process a buffer full of samples pulled from the sample provider
	 * @param buffer Buffer in which the samples are to be processed
	 * @return Count of number of bytes processed
	 */
	public int getSamples(byte [] buffer) {
		
		// Grab samples to manipulate from this modules sample provider
		provider.getSamples(buffer);
		
		int index = 0;
		for (int i = 0; i < SamplePlayer.SAMPLES_PER_BUFFER; i++) {
			// Get a sample to process
			byte b2 = buffer[index];
			byte b1 = buffer[index+1];

			// Convert bytes into short sample
			short s = (short)((b2 << 8) + b1);
			
			// Apply envelope value to sample
			s *= getValue();
			
			// Store the processed sample
			buffer[index++] = (byte)(s >> 8);
			buffer[index++] = (byte)(s & 0xFF);			
		}
		return SamplePlayer.BUFFER_SIZE;
	}	
	// Instance data
	private SampleProviderIntfc provider;
}

The PSynth VCA UI is shown in Figure 2.

Figure 2: PSynth VCA UI.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video