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