Home | History | Annotate | Download | only in webaudio
      1 /*
      2  * Copyright (C) 2010 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  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 
     31 #if ENABLE(WEB_AUDIO)
     32 
     33 #include "modules/webaudio/AudioBuffer.h"
     34 
     35 #include "bindings/core/v8/ExceptionMessages.h"
     36 #include "bindings/core/v8/ExceptionState.h"
     37 #include "bindings/core/v8/custom/V8ArrayBufferCustom.h"
     38 #include "core/dom/ExceptionCode.h"
     39 #include "modules/webaudio/AudioContext.h"
     40 #include "platform/audio/AudioBus.h"
     41 #include "platform/audio/AudioFileReader.h"
     42 #include "platform/audio/AudioUtilities.h"
     43 
     44 namespace blink {
     45 
     46 AudioBuffer* AudioBuffer::create(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
     47 {
     48     if (!AudioUtilities::isValidAudioBufferSampleRate(sampleRate) || numberOfChannels > AudioContext::maxNumberOfChannels() || !numberOfChannels || !numberOfFrames)
     49         return 0;
     50 
     51     AudioBuffer* buffer = new AudioBuffer(numberOfChannels, numberOfFrames, sampleRate);
     52 
     53     if (!buffer->createdSuccessfully(numberOfChannels))
     54         return 0;
     55     return buffer;
     56 }
     57 
     58 AudioBuffer* AudioBuffer::create(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
     59 {
     60     if (!numberOfChannels || numberOfChannels > AudioContext::maxNumberOfChannels()) {
     61         exceptionState.throwDOMException(
     62             NotSupportedError,
     63             ExceptionMessages::indexOutsideRange(
     64                 "number of channels",
     65                 numberOfChannels,
     66                 1u,
     67                 ExceptionMessages::InclusiveBound,
     68                 AudioContext::maxNumberOfChannels(),
     69                 ExceptionMessages::InclusiveBound));
     70         return 0;
     71     }
     72 
     73     if (!AudioUtilities::isValidAudioBufferSampleRate(sampleRate)) {
     74         exceptionState.throwDOMException(
     75             NotSupportedError,
     76             ExceptionMessages::indexOutsideRange(
     77                 "sample rate",
     78                 sampleRate,
     79                 AudioUtilities::minAudioBufferSampleRate(),
     80                 ExceptionMessages::InclusiveBound,
     81                 AudioUtilities::maxAudioBufferSampleRate(),
     82                 ExceptionMessages::InclusiveBound));
     83         return 0;
     84     }
     85 
     86     if (!numberOfFrames) {
     87         exceptionState.throwDOMException(
     88             NotSupportedError,
     89             ExceptionMessages::indexExceedsMinimumBound(
     90                 "number of frames",
     91                 numberOfFrames,
     92                 static_cast<size_t>(0)));
     93         return 0;
     94     }
     95 
     96     AudioBuffer* audioBuffer = create(numberOfChannels, numberOfFrames, sampleRate);
     97 
     98     if (!audioBuffer) {
     99         exceptionState.throwDOMException(
    100             NotSupportedError,
    101             "createBuffer("
    102             + String::number(numberOfChannels) + ", "
    103             + String::number(numberOfFrames) + ", "
    104             + String::number(sampleRate)
    105             + ") failed.");
    106     }
    107 
    108     return audioBuffer;
    109 }
    110 
    111 AudioBuffer* AudioBuffer::createFromAudioFileData(const void* data, size_t dataSize, bool mixToMono, float sampleRate)
    112 {
    113     RefPtr<AudioBus> bus = createBusFromInMemoryAudioFile(data, dataSize, mixToMono, sampleRate);
    114     if (bus.get()) {
    115         AudioBuffer* buffer = new AudioBuffer(bus.get());
    116         if (buffer->createdSuccessfully(bus->numberOfChannels()))
    117             return buffer;
    118     }
    119 
    120     return 0;
    121 }
    122 
    123 AudioBuffer* AudioBuffer::createFromAudioBus(AudioBus* bus)
    124 {
    125     if (!bus)
    126         return 0;
    127     AudioBuffer* buffer = new AudioBuffer(bus);
    128     if (buffer->createdSuccessfully(bus->numberOfChannels()))
    129         return buffer;
    130     return 0;
    131 }
    132 
    133 bool AudioBuffer::createdSuccessfully(unsigned desiredNumberOfChannels) const
    134 {
    135     return numberOfChannels() == desiredNumberOfChannels;
    136 }
    137 
    138 AudioBuffer::AudioBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
    139     : m_sampleRate(sampleRate)
    140     , m_length(numberOfFrames)
    141 {
    142     m_channels.reserveCapacity(numberOfChannels);
    143 
    144     for (unsigned i = 0; i < numberOfChannels; ++i) {
    145         RefPtr<Float32Array> channelDataArray = Float32Array::create(m_length);
    146         // If the channel data array could not be created, just return. The caller will need to
    147         // check that the desired number of channels were created.
    148         if (!channelDataArray) {
    149             return;
    150         }
    151 
    152         channelDataArray->setNeuterable(false);
    153         m_channels.append(channelDataArray);
    154     }
    155 }
    156 
    157 AudioBuffer::AudioBuffer(AudioBus* bus)
    158     : m_sampleRate(bus->sampleRate())
    159     , m_length(bus->length())
    160 {
    161     // Copy audio data from the bus to the Float32Arrays we manage.
    162     unsigned numberOfChannels = bus->numberOfChannels();
    163     m_channels.reserveCapacity(numberOfChannels);
    164     for (unsigned i = 0; i < numberOfChannels; ++i) {
    165         RefPtr<Float32Array> channelDataArray = Float32Array::create(m_length);
    166         // If the channel data array could not be created, just return. The caller will need to
    167         // check that the desired number of channels were created.
    168         if (!channelDataArray)
    169             return;
    170 
    171         channelDataArray->setNeuterable(false);
    172         channelDataArray->setRange(bus->channel(i)->data(), m_length, 0);
    173         m_channels.append(channelDataArray);
    174     }
    175 }
    176 
    177 PassRefPtr<Float32Array> AudioBuffer::getChannelData(unsigned channelIndex, ExceptionState& exceptionState)
    178 {
    179     if (channelIndex >= m_channels.size()) {
    180         exceptionState.throwDOMException(IndexSizeError, "channel index (" + String::number(channelIndex) + ") exceeds number of channels (" + String::number(m_channels.size()) + ")");
    181         return nullptr;
    182     }
    183 
    184     Float32Array* channelData = m_channels[channelIndex].get();
    185     return Float32Array::create(channelData->buffer(), channelData->byteOffset(), channelData->length());
    186 }
    187 
    188 Float32Array* AudioBuffer::getChannelData(unsigned channelIndex)
    189 {
    190     if (channelIndex >= m_channels.size())
    191         return 0;
    192 
    193     return m_channels[channelIndex].get();
    194 }
    195 
    196 void AudioBuffer::zero()
    197 {
    198     for (unsigned i = 0; i < m_channels.size(); ++i) {
    199         if (getChannelData(i))
    200             getChannelData(i)->zeroRange(0, length());
    201     }
    202 }
    203 
    204 v8::Handle<v8::Object> AudioBuffer::associateWithWrapper(const WrapperTypeInfo* wrapperType, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
    205 {
    206     ScriptWrappable::associateWithWrapper(wrapperType, wrapper, isolate);
    207 
    208     if (!wrapper.IsEmpty()) {
    209         // We only setDeallocationObservers on array buffers that are held by
    210         // some object in the V8 heap, not in the ArrayBuffer constructor
    211         // itself. This is because V8 GC only cares about memory it can free on
    212         // GC, and until the object is exposed to JavaScript, V8 GC doesn't
    213         // affect it.
    214         for (unsigned i = 0, n = numberOfChannels(); i < n; ++i) {
    215             getChannelData(i)->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instanceTemplate());
    216         }
    217     }
    218     return wrapper;
    219 }
    220 
    221 } // namespace blink
    222 
    223 #endif // ENABLE(WEB_AUDIO)
    224