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 "core/platform/audio/AudioUtilities.h"
     32 #include "core/platform/audio/VectorMath.h"
     33 #include "modules/webaudio/AudioContext.h"
     34 #include "modules/webaudio/AudioNodeOutput.h"
     35 #include "modules/webaudio/PeriodicWave.h"
     36 #include <algorithm>
     37 #include "wtf/MathExtras.h"
     38 
     39 using namespace std;
     40 
     41 namespace WebCore {
     42 
     43 using namespace VectorMath;
     44 
     45 PeriodicWave* OscillatorNode::s_periodicWaveSine = 0;
     46 PeriodicWave* OscillatorNode::s_periodicWaveSquare = 0;
     47 PeriodicWave* OscillatorNode::s_periodicWaveSawtooth = 0;
     48 PeriodicWave* OscillatorNode::s_periodicWaveTriangle = 0;
     49 
     50 PassRefPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float sampleRate)
     51 {
     52     return adoptRef(new OscillatorNode(context, sampleRate));
     53 }
     54 
     55 OscillatorNode::OscillatorNode(AudioContext* context, float sampleRate)
     56     : AudioScheduledSourceNode(context, sampleRate)
     57     , m_type(SINE)
     58     , m_firstRender(true)
     59     , m_virtualReadIndex(0)
     60     , m_phaseIncrements(AudioNode::ProcessingSizeInFrames)
     61     , m_detuneValues(AudioNode::ProcessingSizeInFrames)
     62 {
     63     ScriptWrappable::init(this);
     64     setNodeType(NodeTypeOscillator);
     65 
     66     // Use musical pitch standard A440 as a default.
     67     m_frequency = AudioParam::create(context, "frequency", 440, 0, 100000);
     68     // Default to no detuning.
     69     m_detune = AudioParam::create(context, "detune", 0, -4800, 4800);
     70 
     71     // Sets up default wavetable.
     72     setType(m_type);
     73 
     74     // An oscillator is always mono.
     75     addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
     76 
     77     initialize();
     78 }
     79 
     80 OscillatorNode::~OscillatorNode()
     81 {
     82     uninitialize();
     83 }
     84 
     85 String OscillatorNode::type() const
     86 {
     87     switch (m_type) {
     88     case SINE:
     89         return "sine";
     90     case SQUARE:
     91         return "square";
     92     case SAWTOOTH:
     93         return "sawtooth";
     94     case TRIANGLE:
     95         return "triangle";
     96     case CUSTOM:
     97         return "custom";
     98     default:
     99         ASSERT_NOT_REACHED();
    100         return "custom";
    101     }
    102 }
    103 
    104 void OscillatorNode::setType(const String& type)
    105 {
    106     if (type == "sine")
    107         setType(SINE);
    108     else if (type == "square")
    109         setType(SQUARE);
    110     else if (type == "sawtooth")
    111         setType(SAWTOOTH);
    112     else if (type == "triangle")
    113         setType(TRIANGLE);
    114     else
    115         ASSERT_NOT_REACHED();
    116 }
    117 
    118 bool OscillatorNode::setType(unsigned type)
    119 {
    120     PeriodicWave* periodicWave = 0;
    121     float sampleRate = this->sampleRate();
    122 
    123     switch (type) {
    124     case SINE:
    125         if (!s_periodicWaveSine)
    126             s_periodicWaveSine = PeriodicWave::createSine(sampleRate).leakRef();
    127         periodicWave = s_periodicWaveSine;
    128         break;
    129     case SQUARE:
    130         if (!s_periodicWaveSquare)
    131             s_periodicWaveSquare = PeriodicWave::createSquare(sampleRate).leakRef();
    132         periodicWave = s_periodicWaveSquare;
    133         break;
    134     case SAWTOOTH:
    135         if (!s_periodicWaveSawtooth)
    136             s_periodicWaveSawtooth = PeriodicWave::createSawtooth(sampleRate).leakRef();
    137         periodicWave = s_periodicWaveSawtooth;
    138         break;
    139     case TRIANGLE:
    140         if (!s_periodicWaveTriangle)
    141             s_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate).leakRef();
    142         periodicWave = s_periodicWaveTriangle;
    143         break;
    144     case CUSTOM:
    145     default:
    146         // Return error for invalid types, including CUSTOM since setPeriodicWave() method must be
    147         // called explicitly.
    148         return false;
    149     }
    150 
    151     setPeriodicWave(periodicWave);
    152     m_type = type;
    153     return true;
    154 }
    155 
    156 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProcess)
    157 {
    158     bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess <= m_detuneValues.size();
    159     ASSERT(isGood);
    160     if (!isGood)
    161         return false;
    162 
    163     if (m_firstRender) {
    164         m_firstRender = false;
    165         m_frequency->resetSmoothedValue();
    166         m_detune->resetSmoothedValue();
    167     }
    168 
    169     bool hasSampleAccurateValues = false;
    170     bool hasFrequencyChanges = false;
    171     float* phaseIncrements = m_phaseIncrements.data();
    172 
    173     float finalScale = m_periodicWave->rateScale();
    174 
    175     if (m_frequency->hasSampleAccurateValues()) {
    176         hasSampleAccurateValues = true;
    177         hasFrequencyChanges = true;
    178 
    179         // Get the sample-accurate frequency values and convert to phase increments.
    180         // They will be converted to phase increments below.
    181         m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProcess);
    182     } else {
    183         // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
    184         m_frequency->smooth();
    185         float frequency = m_frequency->smoothedValue();
    186         finalScale *= frequency;
    187     }
    188 
    189     if (m_detune->hasSampleAccurateValues()) {
    190         hasSampleAccurateValues = true;
    191 
    192         // Get the sample-accurate detune values.
    193         float* detuneValues = hasFrequencyChanges ? m_detuneValues.data() : phaseIncrements;
    194         m_detune->calculateSampleAccurateValues(detuneValues, framesToProcess);
    195 
    196         // Convert from cents to rate scalar.
    197         float k = 1.0 / 1200;
    198         vsmul(detuneValues, 1, &k, detuneValues, 1, framesToProcess);
    199         for (unsigned i = 0; i < framesToProcess; ++i)
    200             detuneValues[i] = powf(2, detuneValues[i]); // FIXME: converting to expf() will be faster.
    201 
    202         if (hasFrequencyChanges) {
    203             // Multiply frequencies by detune scalings.
    204             vmul(detuneValues, 1, phaseIncrements, 1, phaseIncrements, 1, framesToProcess);
    205         }
    206     } else {
    207         // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
    208         m_detune->smooth();
    209         float detune = m_detune->smoothedValue();
    210         float detuneScale = powf(2, detune / 1200);
    211         finalScale *= detuneScale;
    212     }
    213 
    214     if (hasSampleAccurateValues) {
    215         // Convert from frequency to wavetable increment.
    216         vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess);
    217     }
    218 
    219     return hasSampleAccurateValues;
    220 }
    221 
    222 void OscillatorNode::process(size_t framesToProcess)
    223 {
    224     AudioBus* outputBus = output(0)->bus();
    225 
    226     if (!isInitialized() || !outputBus->numberOfChannels()) {
    227         outputBus->zero();
    228         return;
    229     }
    230 
    231     ASSERT(framesToProcess <= m_phaseIncrements.size());
    232     if (framesToProcess > m_phaseIncrements.size())
    233         return;
    234 
    235     // The audio thread can't block on this lock, so we call tryLock() instead.
    236     MutexTryLocker tryLocker(m_processLock);
    237     if (!tryLocker.locked()) {
    238         // Too bad - the tryLock() failed. We must be in the middle of changing wave-tables.
    239         outputBus->zero();
    240         return;
    241     }
    242 
    243     // We must access m_periodicWave only inside the lock.
    244     if (!m_periodicWave.get()) {
    245         outputBus->zero();
    246         return;
    247     }
    248 
    249     size_t quantumFrameOffset;
    250     size_t nonSilentFramesToProcess;
    251 
    252     updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSilentFramesToProcess);
    253 
    254     if (!nonSilentFramesToProcess) {
    255         outputBus->zero();
    256         return;
    257     }
    258 
    259     unsigned periodicWaveSize = m_periodicWave->periodicWaveSize();
    260     double invPeriodicWaveSize = 1.0 / periodicWaveSize;
    261 
    262     float* destP = outputBus->channel(0)->mutableData();
    263 
    264     ASSERT(quantumFrameOffset <= framesToProcess);
    265 
    266     // We keep virtualReadIndex double-precision since we're accumulating values.
    267     double virtualReadIndex = m_virtualReadIndex;
    268 
    269     float rateScale = m_periodicWave->rateScale();
    270     float invRateScale = 1 / rateScale;
    271     bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess);
    272 
    273     float frequency = 0;
    274     float* higherWaveData = 0;
    275     float* lowerWaveData = 0;
    276     float tableInterpolationFactor;
    277 
    278     if (!hasSampleAccurateValues) {
    279         frequency = m_frequency->smoothedValue();
    280         float detune = m_detune->smoothedValue();
    281         float detuneScale = powf(2, detune / 1200);
    282         frequency *= detuneScale;
    283         m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
    284     }
    285 
    286     float incr = frequency * rateScale;
    287     float* phaseIncrements = m_phaseIncrements.data();
    288 
    289     unsigned readIndexMask = periodicWaveSize - 1;
    290 
    291     // Start rendering at the correct offset.
    292     destP += quantumFrameOffset;
    293     int n = nonSilentFramesToProcess;
    294 
    295     while (n--) {
    296         unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
    297         unsigned readIndex2 = readIndex + 1;
    298 
    299         // Contain within valid range.
    300         readIndex = readIndex & readIndexMask;
    301         readIndex2 = readIndex2 & readIndexMask;
    302 
    303         if (hasSampleAccurateValues) {
    304             incr = *phaseIncrements++;
    305 
    306             frequency = invRateScale * incr;
    307             m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
    308         }
    309 
    310         float sample1Lower = lowerWaveData[readIndex];
    311         float sample2Lower = lowerWaveData[readIndex2];
    312         float sample1Higher = higherWaveData[readIndex];
    313         float sample2Higher = higherWaveData[readIndex2];
    314 
    315         // Linearly interpolate within each table (lower and higher).
    316         float interpolationFactor = static_cast<float>(virtualReadIndex) - readIndex;
    317         float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpolationFactor * sample2Higher;
    318         float sampleLower = (1 - interpolationFactor) * sample1Lower + interpolationFactor * sample2Lower;
    319 
    320         // Then interpolate between the two tables.
    321         float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInterpolationFactor * sampleLower;
    322 
    323         *destP++ = sample;
    324 
    325         // Increment virtual read index and wrap virtualReadIndex into the range 0 -> periodicWaveSize.
    326         virtualReadIndex += incr;
    327         virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * periodicWaveSize;
    328     }
    329 
    330     m_virtualReadIndex = virtualReadIndex;
    331 
    332     outputBus->clearSilentFlag();
    333 }
    334 
    335 void OscillatorNode::reset()
    336 {
    337     m_virtualReadIndex = 0;
    338 }
    339 
    340 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave)
    341 {
    342     ASSERT(isMainThread());
    343 
    344     // This synchronizes with process().
    345     MutexLocker processLocker(m_processLock);
    346     m_periodicWave = periodicWave;
    347     m_type = CUSTOM;
    348 }
    349 
    350 bool OscillatorNode::propagatesSilence() const
    351 {
    352     return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get();
    353 }
    354 
    355 } // namespace WebCore
    356 
    357 #endif // ENABLE(WEB_AUDIO)
    358