Package net.paulhertz.pixelaudio

# Class WaveSynth

java.lang.Object
net.paulhertz.pixelaudio.WaveSynth

public class WaveSynth extends Object
Implements a combination of color organ and additive audio synth. Animates pixels using phase shifting of audio generators in `waveDataList`. WaveSynth is organized around properties, such as gain (i.e. loudness or brightness) and gamma (a sort of contrast setting), and data objects. The data objects include a a bitmap, mapImage, that is a Processing PImage instance for the image representation of the WaveSynth, a PixelAudioMapper that allows the WaveSynth to mediate between audio data and image data, arrays for the WaveSynth's audio signal and the image data ordered by the PixelAudioMapper signal path, and an array of WaveData objects, waveDataList, that holds the individual sine wave components of the WaveSynth with their frequency, amplitude, phase, and other properties. There are also a series of properties concerned with animation and video output. When a WaveSynth is used to produce color patterns, each WaveData object in the waveDataList controls a color. The colors of the various WaveData objects are added together, much as the audio sine waves are to produce audio, with the brightness of each color determined by the amplitude of the controlling sine wave. The WaveSynthAnimation example code provides a graphical user interface for editing the WaveSynth properties and the individual WaveData objects. Experimenting with it to get an idea of what WaveSynth can do to produce patterns. Gamma and histogram scaling are intended primarily for still-image grading and offline rendering. For realtime animation, prefer adjusting operator amplitudes and DC offsets to control brightness/contrast, and leave gamma = 1.0 and isScaleHisto = false for best performance.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `private float[]`
  `activeColorB`
  `private float[]`
  `activeColorG`
  `private float[]`
  `activeColorR`
  Pre-split color channels for active waves (first activeCount entries valid).
  `private int`
  `activeCount`
  `private WaveData[]`
  `activeWaves`
  Active (unmuted, non-suspended) waves for current frame.
  `private float[]`
  `activeWeights`
  Weights just for active waves (first activeCount entries valid).
  `int`
  `animSteps`
  `float[]`
  `audioSignal`
  `int[]`
  `colorSignal`
  `String`
  `comments`
  comments for JSON file
  `int`
  `dataLength`
  `float`
  `gain`
  `float`
  `gamma`
  `int[]`
  `gammaTable`
  `private int`
  `h`
  `int`
  `histoHigh`
  `int`
  `histoLow`
  `(package private) boolean`
  `isRenderAudio`
  `boolean`
  `isScaleHisto`
  `processing.core.PImage`
  `mapImage`
  `float`
  `mapInc`
  the increment in phase over the image pixels, typically TWO_PI / image size
  `PixelAudioMapper`
  `mapper`
  `int`
  `mapSize`
  `int[]`
  `maskScan`
  array of color values for mask, especially useful when it is constant
  `float`
  `noisiness`
  `float[]`
  `renderSignal`
  `float`
  `sampleRate`
  The sampling frequency, the number of samples read in one second of sound.
  `int`
  `step`
  `int`
  `stop`
  `boolean`
  `useGammaTable`
  `String`
  `videoFilename`
  `int`
  `videoFrameRate`
  `private int`
  `w`
  `int[]`
  `waveColors`
  array of colors associated with the WaveData operators
  `ArrayList<WaveData>`
  `waveDataList`
  `float[]`
  `weights`
  array of amplitudes associated with the WaveData operators
  `float`
  `woff`
  offset for normailzing signal, see renderFrame method
  `float`
  `wscale`
  scaling facotr for normalizing signal, see renderFrame method

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `WaveSynth(PixelAudioMapper mapper)`
  `WaveSynth(PixelAudioMapper mapper, ArrayList<WaveData> wdList)`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `WaveSynth`
  `clone()`
  `int`
  `getAnimSteps()`
  `String`
  `getComments()`
  `float`
  `getGain()`
  `float`
  `getGamma()`
  `int`
  `getHeight()`
  `static int[]`
  `getHistoBounds(int[] source)`
  `int`
  `getHistoHigh()`
  `int`
  `getHistoLow()`
  `PixelAudioMapper`
  `getMapper()`
  `float`
  `getNoiseiness()`
  `float`
  `getSampleRate()`
  `int`
  `getStep()`
  `int`
  `getStop()`
  `String`
  `getVideoFilename()`
  `int`
  `getVideoFrameRate()`
  `ArrayList<WaveData>`
  `getWaveDataList()`
  `int`
  `getWidth()`
  `boolean`
  `isRenderAudio()`
  `boolean`
  `isScaleHisto()`
  `float`
  `noiseAt(int x, int y)`
  `static float[]`
  `normalize(float[] sig)`
  `static float[]`
  `normalize(float[] sig, float limit)`
  `void`
  `prepareAnimation()`
  Legacy code: set up mapImage for editing, load colorSignal, set mapInc.
  `static ArrayList<WaveData>`
  `quickWaveDataList()`
  Initializes a list of WaveData for use by a WaveSynth.
  `private void`
  `rebuildActiveWaves()`
  Rebuilds the list of active (unmuted, non-suspended) waves and pre-splits their colors into RGB channels.
  `float[]`
  `renderAudio(int frame)`
  `float[]`
  `renderAudio(int frame, float limit)`
  `float[]`
  `renderAudioRaw(int frame)`
  `processing.core.PImage`
  `renderFrame(int frame)`
  Loop to render all the pixels in a frame.
  `int`
  `renderPixel(int frame, int pos, ArrayList<WaveData> wdList)`
  Render one pixel, return its RGB value.
  `void`
  `setAnimSteps(int animSteps)`
  `void`
  `setComments(String comments)`
  `void`
  `setGain(float gain)`
  `void`
  `setGamma(float gamma)`
  `void`
  `setHistoHigh(int histoHigh)`
  `void`
  `setHistoLow(int histoLow)`
  `void`
  `setMapper(PixelAudioMapper mapper)`
  `void`
  `setNoiseiness(float noiseiness)`
  `void`
  `setRenderAudio(boolean isRenderAudio)`
  `void`
  `setSampleRate(float newSampleRate)`
  `void`
  `setScaleHisto(boolean isScaleHisto)`
  `void`
  `setStep(int step)`
  `void`
  `setStop(int stop)`
  `void`
  `setVideoFilename(String videoFilename)`
  `void`
  `setVideoFrameRate(int videoFrameRate)`
  `void`
  `setWaveData(ArrayList<WaveData> wdList)`
  `void`
  `setWaveDataList(ArrayList<WaveData> waveDataList)`
  `static int[]`
  `stretch(int[] source, int low, int high)`
  `String`
  `toString()`
  `void`
  `updateWaveColors()`
  `int`
  `weightedColor(int[] colors, float[] weights)`
  `private int`
  `weightedColorActive(float[] weights, int count)`
  Optimized weighted color for the current active waves.

  ### Methods inherited from class java.lang.Object

  `equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

- ## Field Details

  - ### mapper

    public PixelAudioMapper mapper

  - ### mapImage

    public processing.core.PImage mapImage

  - ### colorSignal

    public int[] colorSignal

  - ### audioSignal

    public float[] audioSignal

  - ### renderSignal

    public float[] renderSignal

  - ### waveDataList

    public ArrayList<WaveData> waveDataList

  - ### isRenderAudio

    boolean isRenderAudio

  - ### w

    private int w

  - ### h

    private int h

  - ### mapSize

    public int mapSize

  - ### dataLength

    public int dataLength

  - ### gain

    public float gain

  - ### gamma

    public float gamma

  - ### gammaTable

    public int[] gammaTable

  - ### useGammaTable

    public boolean useGammaTable

  - ### isScaleHisto

    public boolean isScaleHisto

  - ### histoLow

    public int histoLow

  - ### histoHigh

    public int histoHigh

  - ### animSteps

    public int animSteps

  - ### step

    public int step

  - ### stop

    public int stop

  - ### noisiness

    public float noisiness

  - ### comments

    public String comments
    comments for JSON file

  - ### sampleRate

    public float sampleRate
    The sampling frequency, the number of samples read in one second of sound. By default, for WaveSynth instances that are intended to be primarily visual, mapSize is the sampling frequency. This makes one period of a 1.0 Hz wave fill the entire signal curve. OTOH, if we want the image to represent an audio signal that is also produced by additive synthesis, we should set samplingFrequency to a standard such as 44100 or 48000.

  - ### mapInc

    public float mapInc
    the increment in phase over the image pixels, typically TWO_PI / image size

  - ### weights

    public float[] weights
    array of amplitudes associated with the WaveData operators

  - ### waveColors

    public int[] waveColors
    array of colors associated with the WaveData operators

  - ### maskScan

    public int[] maskScan
    array of color values for mask, especially useful when it is constant

  - ### woff

    public float woff
    offset for normailzing signal, see renderFrame method

  - ### wscale

    public float wscale
    scaling facotr for normalizing signal, see renderFrame method

  - ### videoFrameRate

    public int videoFrameRate

  - ### videoFilename

    public String videoFilename

  - ### activeWaves

    private WaveData[] activeWaves
    Active (unmuted, non-suspended) waves for current frame.

  - ### activeCount

    private int activeCount

  - ### activeWeights

    private float[] activeWeights
    Weights just for active waves (first activeCount entries valid).

  - ### activeColorR

    private float[] activeColorR
    Pre-split color channels for active waves (first activeCount entries valid).

  - ### activeColorG

    private float[] activeColorG

  - ### activeColorB

    private float[] activeColorB

- ## Constructor Details

  - ### WaveSynth

    public WaveSynth(PixelAudioMapper mapper, ArrayList<WaveData> wdList)

  - ### WaveSynth

    public WaveSynth(PixelAudioMapper mapper)

- ## Method Details

  - ### setMapper

    public void setMapper(PixelAudioMapper mapper)

  - ### setWaveData

    public void setWaveData(ArrayList<WaveData> wdList)

  - ### updateWaveColors

    public void updateWaveColors()

  - ### rebuildActiveWaves

    private void rebuildActiveWaves()
    Rebuilds the list of active (unmuted, non-suspended) waves and pre-splits their colors into RGB channels.

  - ### quickWaveDataList

    public static ArrayList<WaveData> quickWaveDataList()
    Initializes a list of WaveData for use by a WaveSynth.
    Returns:
      an ArrayList of WaveData objects

  - ### getWaveDataList

    public ArrayList<WaveData> getWaveDataList()

  - ### setWaveDataList

    public void setWaveDataList(ArrayList<WaveData> waveDataList)

  - ### getGain

    public float getGain()

  - ### setGain

    public void setGain(float gain)

  - ### getGamma

    public float getGamma()

  - ### setGamma

    public void setGamma(float gamma)

  - ### isScaleHisto

    public boolean isScaleHisto()

  - ### setScaleHisto

    public void setScaleHisto(boolean isScaleHisto)

  - ### getHistoLow

    public int getHistoLow()

  - ### setHistoLow

    public void setHistoLow(int histoLow)

  - ### getHistoHigh

    public int getHistoHigh()

  - ### setHistoHigh

    public void setHistoHigh(int histoHigh)

  - ### getNoiseiness

    public float getNoiseiness()

  - ### setNoiseiness

    public void setNoiseiness(float noiseiness)

  - ### getAnimSteps

    public int getAnimSteps()

  - ### setAnimSteps

    public void setAnimSteps(int animSteps)

  - ### getStop

    public int getStop()

  - ### setStop

    public void setStop(int stop)

  - ### getStep

    public int getStep()

  - ### setStep

    public void setStep(int step)

  - ### getComments

    public String getComments()

  - ### setComments

    public void setComments(String comments)

  - ### getVideoFrameRate

    public int getVideoFrameRate()

  - ### setVideoFrameRate

    public void setVideoFrameRate(int videoFrameRate)

  - ### getVideoFilename

    public String getVideoFilename()

  - ### setVideoFilename

    public void setVideoFilename(String videoFilename)

  - ### getMapper

    public PixelAudioMapper getMapper()

  - ### getWidth

    public int getWidth()

  - ### getHeight

    public int getHeight()

  - ### getSampleRate

    public float getSampleRate()

  - ### setSampleRate

    public void setSampleRate(float newSampleRate)

  - ### clone

    public WaveSynth clone()
    Overrides:
      `clone` in class `Object`

  - ### toString

    public String toString()
    Overrides:
      `toString` in class `Object`

  - ### isRenderAudio

    public boolean isRenderAudio()

  - ### setRenderAudio

    public void setRenderAudio(boolean isRenderAudio)

  - ### prepareAnimation

    public void prepareAnimation()
    Legacy code: set up mapImage for editing, load colorSignal, set mapInc. colorSignal = mapper.pluckPixels(...) is no longer essential, because renderFrame() overwrites every colorSignal[pos] before planting it back into mapImage.pixels.

  - ### renderFrame

    public processing.core.PImage renderFrame(int frame)
    Loop to render all the pixels in a frame. We want it to complete a frame before any changes to the WaveSynth, so it's synchronized.
    Parameters:
      `frame` - the number of the frame we are rendering in an animation sequence
    Returns:
      a PImage derived from additive audio synthesis.

  - ### weightedColorActive

    private int weightedColorActive(float[] weights, int count)
    Optimized weighted color for the current active waves. Uses pre-split RGB and only the first activeCount entries. Gamma and Histogram settings are primarily intended for still frame rendering. You can probably tweak operator amplitudes and perhaps DC offset to obtain the brightness and contrast you want for animation. Leave gamma = 1.0 and isScaleHisto = false for best performance.

  - ### renderPixel

    public int renderPixel(int frame, int pos, ArrayList<WaveData> wdList)
    Render one pixel, return its RGB value. NOTES Our basic equation: ::::: sample amplitude = sin(initial phase + phase shift + frequency * i * (TWO_PI/n)) ::::: Restated, in two parts: wd.phaseInc = (wd.cycles * TWO_PI)/animSteps; mapInc = TWO_PI / mapSize; float val = (float) (Math.sin(wd.phaseTwoPi - frame * wd.phaseInc + wd.freq * freqShift * pos * mapInc) + woff) * wscale + wd.dc; Instead of incrementing phase at each step, we subtract (frame * phase increment) from the initial phase: instead of adding, we subtract so that animation data files give the same result in previous implementations. And yes, I have forgotten the original reasons for subtracting. For the latest version: We now let the WaveData object calculate the signal: this is much more flexible and barely affects the time.
    Parameters:
      `frame` -
      `pos` -
      `wdList` -
    Returns:

  - ### weightedColor

    public int weightedColor(int[] colors, float[] weights)

  - ### renderAudio

    public float[] renderAudio(int frame)

  - ### renderAudioRaw

    public float[] renderAudioRaw(int frame)

  - ### renderAudio

    public float[] renderAudio(int frame, float limit)

  - ### noiseAt

    public float noiseAt(int x, int y)

  - ### normalize

    public static float[] normalize(float[] sig, float limit)

  - ### normalize

    public static float[] normalize(float[] sig)

  - ### getHistoBounds

    public static int[] getHistoBounds(int[] source)

  - ### stretch

    public static int[] stretch(int[] source, int low, int high)