JVM Languages

Music Components in Java: Creating Oscillators

By Craig Lindley, June 09, 2011

Develop simple and complex oscillators in software and manipulate the resulting wave forms. And suddenly, music!

The getSamples method repeatedly calls getSample where the actual samples are generated. getSample returns a double that must be scaled and converted to a short integer value (because of our sample definition in SamplePlayer uses short integers) before being broken into two bytes, which are stored sequentially in the sample buffer. When the buffer is full, the getSamples method returns, which effectively passes the oscillator samples to the next component in the signal chain.

The getSample method is where sample generation takes place. Here a counter is set up. It counts from zero to the number of sample times required for a complete period of the selected wave shape at the selected frequency. Sine wave samples are calculated using the sin math function. A square wave is produced by setting the output to +1.0 for the first half of the waveform period and to -1.0 for the second half. A sawtooth wave shape is produced using characteristics of the floor math function. The wave shape produced is determined by the waveshape variable in conjunction with the switch statement in the code.

BasicOscillator's setFrequency method is called to set the frequency produced by the oscillator. The setWaveshape method is called to set the type of wave shape the oscillator produces.

To hear a BasicOscillator in action it must be coupled with a SamplePlayer as the following code illustrates.

// Create an oscillator sample producer
BasicOscillator osc = new BasicOscillator();
// Set the frequency
osc.setFrequency(500);
// Set the waveashape
osc.setWaveshape(WAVESHAPE.SIN);
// Create a sample player
SamplePlayer player = new SamplePlayer();
// Sets the player's sample provider
player.setSampleProvider(osc);
// Start the player
player.startPlayer();
// Delay so oscillator can be heard
delay(1000 * 4);
// Stop the player
player.stopPlayer();

Remember, SamplerPlayer will pull samples from its sample provider (the BasicOscillator) at the rate it needs for uninterrupted sound production.

The AdvancedOscillator

As functional as the BasicOscillator is, it lacks some features that would make it useful for electronic music. If, however, you combine two BasicOscillator instances and some glue code you end up with a very versatile device. PSynth's oscillator, which has a superset of the AdvancedOscillator functionality, is shown in Figure 1.

[Click image to view at full size]

Figure 1: The oscillator component from PSynth.

AdvancedOscillator features include:

The ability to set the frequency of the oscillator

The ability to set the wave shape of the oscillator

The ability to alter the range of the oscillator independent of the frequency selected

The ability to detune the oscillator by any number of cents

Incorporation of a Low Frequency Oscillator (LFO) as the modulation source. Along with the ability to set the LFO's frequency, wave shape and modulation depth.

The ability to use amplitude modulation (discussed in Part 1 of this series).

The ability to use frequency modulation (see Part 1).

The AdvancedOscillator's code is too long to be reproduced here so see the Resources section at the end of this article to obtain the code.

The important thing to understand is one of the BasicOscillator instances (call it osc #1) produces the sound that will be heard while the other oscillator (osc #2) functions as an LFO for modulating osc #1.

Implementation wise, AdvancedOscillator extends BasicOscillator for osc #1 functionality and it has a BasicOscillator (lfo) for use as osc #2.

AdvancedOscillator's getSample method shows how osc #2 can be made for amplitude or frequency modulation of osc #1.:

While examining this code remember that FM modulation varies the frequency produced by osc #1 whereas AM modulation varies the amplitude produced by osc #1.

The Envelope Generator

An envelope generator (EG), which may also be called an ADSR for Attack, Decay, Sustain and Release, generates a time varying control signal used to control some other device. PSynth's envelope generator / amplitude module UI is shown in Figure 2. The EG described here is implemented by the EnvelopeGenerator class. See the javadocs for the complete API. Here, I’ll first describe what an EG does and then describe how it does it.

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.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!