Channels ▼
RSS

JVM Languages

Music Components in Java: Creating Oscillators


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:

  1. The ability to set the frequency of the oscillator
  2. The ability to set the wave shape of the oscillator
  3. The ability to alter the range of the oscillator independent of the frequency selected
  4. The ability to detune the oscillator by any number of cents
  5. 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.
  6. The ability to use amplitude modulation (discussed in Part 1 of this series).
  7. 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.:

  /**
   * Return the next sample of the oscillator's waveform
   *
   * @return Next oscillator sample
   */
  protected double getSample() {

    double freq = frequency;

    // Are we frequency modulating
    if ((modulationType == MOD_TYPE.FM) && (modulationDepth != 0.0)) {
      double lfoValue = lfo.getSample() * modulationDepth;
      freq *= Math.pow(2.0, lfoValue);
    }
    // Apply frequency multiplier
    freq *= rangeMultiplier;

    // Apply detuning multiplier
    freq *= detuneMultiplier;
    
    // Set frequency of osc
    super.setFrequency(freq);

    // Get an osc sample
    double sample = super.getSample();

    // Are we amplitude modulating
    if (modulationType == MOD_TYPE.AM)  {
      double lfoOffset = (lfo.getSample() + 1.0) / 2.0;
      double m = 1.0 - (modulationDepth * lfoOffset);
      sample *=  m;
    }
    // Return the osc sample
    return sample;
  }

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.

[Click image to view at full size]
Figure 2: The envelope generator/amplitude module UI in PSynth.


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