Home | History | Annotate | Download | only in webaudio
      1 /*
      2  * Copyright (C) 2012, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #if ENABLE(WEB_AUDIO)
     28 
     29 #include "modules/webaudio/OscillatorNode.h"
     30 
     31 #include "platform/audio/AudioUtilities.h"
     32 #include "platform/audio/VectorMath.h"
     33 #include "modules/webaudio/AudioContext.h"
     34 #include "modules/webaudio/AudioNodeOutput.h"
     35 #include "modules/webaudio/PeriodicWave.h"
     36 #include "wtf/MathExtras.h"
     37 #include "wtf/StdLibExtras.h"
     38 #include <algorithm>
     39 
     40 namespace blink {
     41 
     42 using namespace VectorMath;
     43 
     44 OscillatorNode* OscillatorNode::create(AudioContext* context, float sampleRate)
     45 {
     46     return adoptRefCountedGarbageCollectedWillBeNoop(new OscillatorNode(context, sampleRate));
     47 }
     48 
     49 OscillatorNode::OscillatorNode(AudioContext* context, float sampleRate)
     50     : AudioScheduledSourceNode(context, sampleRate)
     51     , m_type(SINE)
     52     , m_firstRender(true)
     53     , m_virtualReadIndex(0)
     54     , m_phaseIncrements(AudioNode::ProcessingSizeInFrames)
     55     , m_detuneValues(AudioNode::ProcessingSizeInFrames)
     56 {
     57     setNodeType(NodeTypeOscillator);
     58 
     59     // Use musical pitch standard A440 as a default.
     60     m_frequency = AudioParam::create(context, 440);
     61     // Default to no detuning.
     62     m_detune = AudioParam::create(context, 0);
     63 
     64     // Sets up default wavetable.
     65     setType(m_type);
     66 
     67     // An oscillator is always mono.
     68     addOutput(AudioNodeOutput::create(this, 1));
     69 
     70     initialize();
     71 }
     72 
     73 OscillatorNode::~OscillatorNode()
     74 {
     75     ASSERT(!isInitialized());
     76 }
     77 
     78 void OscillatorNode::dispose()
     79 {
     80     uninitialize();
     81     AudioScheduledSourceNode::dispose();
     82 }
     83 
     84 String OscillatorNode::type() const
     85 {
     86     switch (m_type) {
     87     case SINE:
     88         return "sine";
     89     case SQUARE:
     90         return "square";
     91     case SAWTOOTH:
     92         return "sawtooth";
     93     case TRIANGLE:
     94         return "triangle";
     95     case CUSTOM:
     96         return "custom";
     97     default:
     98         ASSERT_NOT_REACHED();
     99         return "custom";
    100     }
    101 }
    102 
    103 void OscillatorNode::setType(const String& type)
    104 {
    105     if (type == "sine")
    106         setType(SINE);
    107     else if (type == "square")
    108         setType(SQUARE);
    109     else if (type == "sawtooth")
    110         setType(SAWTOOTH);
    111     else if (type == "triangle")
    112         setType(TRIANGLE);
    113 }
    114 
    115 bool OscillatorNode::setType(unsigned type)
    116 {
    117     PeriodicWave* periodicWave = 0;
    118     float sampleRate = this->sampleRate();
    119 
    120     switch (type) {
    121     case SINE: {
    122         DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveSine, (PeriodicWave::createSine(sampleRate)));
    123         periodicWave = periodicWaveSine;
    124         break;
    125     }
    126     case SQUARE: {
    127         DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveSquare, (PeriodicWave::createSquare(sampleRate)));
    128         periodicWave = periodicWaveSquare;
    129         break;
    130     }
    131     case SAWTOOTH: {
    132         DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveSawtooth, (PeriodicWave::createSawtooth(sampleRate)));
    133         periodicWave = periodicWaveSawtooth;
    134         break;
    135     }
    136     case TRIANGLE: {
    137         DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveTriangle, (PeriodicWave::createTriangle(sampleRate)));
    138         periodicWave = periodicWaveTriangle;
    139         break;
    140     }
    141     case CUSTOM:
    142     default:
    143         // Return error for invalid types, including CUSTOM since setPeriodicWave() method must be
    144         // called explicitly.
    145         return false;
    146     }
    147 
    148     setPeriodicWave(periodicWave);
    149     m_type = type;
    150     return true;
    151 }
    152 
    153 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProcess)
    154 {
    155     bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess <= m_detuneValues.size();
    156     ASSERT(isGood);
    157     if (!isGood)
    158         return false;
    159 
    160     if (m_firstRender) {
    161         m_firstRender = false;
    162         m_frequency->resetSmoothedValue();
    163         m_detune->resetSmoothedValue();
    164     }
    165 
    166     bool hasSampleAccurateValues = false;
    167     bool hasFrequencyChanges = false;
    168     float* phaseIncrements = m_phaseIncrements.data();
    169 
    170     float finalScale = m_periodicWave->rateScale();
    171 
    172     if (m_frequency->hasSampleAccurateValues()) {
    173         hasSampleAccurateValues = true;
    174         hasFrequencyChanges = true;
    175 
    176         // Get the sample-accurate frequency values and convert to phase increments.
    177         // They will be converted to phase increments below.
    178         m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProcess);
    179     } else {
    180         // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
    181         m_frequency->smooth();
    182         float frequency = m_frequency->smoothedValue();
    183         finalScale *= frequency;
    184     }
    185 
    186     if (m_detune->hasSampleAccurateValues()) {
    187         hasSampleAccurateValues = true;
    188 
    189         // Get the sample-accurate detune values.
    190         float* detuneValues = hasFrequencyChanges ? m_detuneValues.data() : phaseIncrements;
    191         m_detune->calculateSampleAccurateValues(detuneValues, framesToProcess);
    192 
    193         // Convert from cents to rate scalar.
    194         float k = 1.0 / 1200;
    195         vsmul(detuneValues, 1, &k, detuneValues, 1, framesToProcess);
    196         for (unsigned i = 0; i < framesToProcess; ++i)
    197             detuneValues[i] = powf(2, detuneValues[i]); // FIXME: converting to expf() will be faster.
    198 
    199         if (hasFrequencyChanges) {
    200             // Multiply frequencies by detune scalings.
    201             vmul(detuneValues, 1, phaseIncrements, 1, phaseIncrements, 1, framesToProcess);
    202         }
    203     } else {
    204         // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
    205         m_detune->smooth();
    206         float detune = m_detune->smoothedValue();
    207         float detuneScale = powf(2, detune / 1200);
    208         finalScale *= detuneScale;
    209     }
    210 
    211     if (hasSampleAccurateValues) {
    212         // Convert from frequency to wavetable increment.
    213         vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess);
    214     }
    215 
    216     return hasSampleAccurateValues;
    217 }
    218 
    219 void OscillatorNode::process(size_t framesToProcess)
    220 {
    221     AudioBus* outputBus = output(0)->bus();
    222 
    223     if (!isInitialized() || !outputBus->numberOfChannels()) {
    224         outputBus->zero();
    225         return;
    226     }
    227 
    228     ASSERT(framesToProcess <= m_phaseIncrements.size());
    229     if (framesToProcess > m_phaseIncrements.size())
    230         return;
    231 
    232     // The audio thread can't block on this lock, so we call tryLock() instead.
    233     MutexTryLocker tryLocker(m_processLock);
    234     if (!tryLocker.locked()) {
    235         // Too bad - the tryLock() failed. We must be in the middle of changing wave-tables.
    236         outputBus->zero();
    237         return;
    238     }
    239 
    240     // We must access m_periodicWave only inside the lock.
    241     if (!m_periodicWave.get()) {
    242         outputBus->zero();
    243         return;
    244     }
    245 
    246     size_t quantumFrameOffset;
    247     size_t nonSilentFramesToProcess;
    248 
    249     updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSilentFramesToProcess);
    250 
    251     if (!nonSilentFramesToProcess) {
    252         outputBus->zero();
    253         return;
    254     }
    255 
    256     unsigned periodicWaveSize = m_periodicWave->periodicWaveSize();
    257     double invPeriodicWaveSize = 1.0 / periodicWaveSize;
    258 
    259     float* destP = outputBus->channel(0)->mutableData();
    260 
    261     ASSERT(quantumFrameOffset <= framesToProcess);
    262 
    263     // We keep virtualReadIndex double-precision since we're accumulating values.
    264     double virtualReadIndex = m_virtualReadIndex;
    265 
    266     float rateScale = m_periodicWave->rateScale();
    267     float invRateScale = 1 / rateScale;
    268     bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess);
    269 
    270     float frequency = 0;
    271     float* higherWaveData = 0;
    272     float* lowerWaveData = 0;
    273     float tableInterpolationFactor = 0;
    274 
    275     if (!hasSampleAccurateValues) {
    276         frequency = m_frequency->smoothedValue();
    277         float detune = m_detune->smoothedValue();
    278         float detuneScale = powf(2, detune / 1200);
    279         frequency *= detuneScale;
    280         m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
    281     }
    282 
    283     float incr = frequency * rateScale;
    284     float* phaseIncrements = m_phaseIncrements.data();
    285 
    286     unsigned readIndexMask = periodicWaveSize - 1;
    287 
    288     // Start rendering at the correct offset.
    289     destP += quantumFrameOffset;
    290     int n = nonSilentFramesToProcess;
    291 
    292     while (n--) {
    293         unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
    294         unsigned readIndex2 = readIndex + 1;
    295 
    296         // Contain within valid range.
    297         readIndex = readIndex & readIndexMask;
    298         readIndex2 = readIndex2 & readIndexMask;
    299 
    300         if (hasSampleAccurateValues) {
    301             incr = *phaseIncrements++;
    302 
    303             frequency = invRateScale * incr;
    304             m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
    305         }
    306 
    307         float sample1Lower = lowerWaveData[readIndex];
    308         float sample2Lower = lowerWaveData[readIndex2];
    309         float sample1Higher = higherWaveData[readIndex];
    310         float sample2Higher = higherWaveData[readIndex2];
    311 
    312         // Linearly interpolate within each table (lower and higher).
    313         float interpolationFactor = static_cast<float>(virtualReadIndex) - readIndex;
    314         float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpolationFactor * sample2Higher;
    315         float sampleLower = (1 - interpolationFactor) * sample1Lower + interpolationFactor * sample2Lower;
    316 
    317         // Then interpolate between the two tables.
    318         float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInterpolationFactor * sampleLower;
    319 
    320         *destP++ = sample;
    321 
    322         // Increment virtual read index and wrap virtualReadIndex into the range 0 -> periodicWaveSize.
    323         virtualReadIndex += incr;
    324         virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * periodicWaveSize;
    325     }
    326 
    327     m_virtualReadIndex = virtualReadIndex;
    328 
    329     outputBus->clearSilentFlag();
    330 }
    331 
    332 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave)
    333 {
    334     ASSERT(isMainThread());
    335 
    336     // This synchronizes with process().
    337     MutexLocker processLocker(m_processLock);
    338     m_periodicWave = periodicWave;
    339     m_type = CUSTOM;
    340 }
    341 
    342 bool OscillatorNode::propagatesSilence() const
    343 {
    344     return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get();
    345 }
    346 
    347 void OscillatorNode::trace(Visitor* visitor)
    348 {
    349     visitor->trace(m_frequency);
    350     visitor->trace(m_detune);
    351     visitor->trace(m_periodicWave);
    352     AudioScheduledSourceNode::trace(visitor);
    353 }
    354 
    355 } // namespace blink
    356 
    357 #endif // ENABLE(WEB_AUDIO)
    358