AudioBuffer.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/Completion.h>
  7. #include <LibJS/Runtime/Realm.h>
  8. #include <LibJS/Runtime/TypedArray.h>
  9. #include <LibJS/Runtime/VM.h>
  10. #include <LibWeb/Bindings/AudioBufferPrototype.h>
  11. #include <LibWeb/Bindings/Intrinsics.h>
  12. #include <LibWeb/WebAudio/AudioBuffer.h>
  13. #include <LibWeb/WebAudio/BaseAudioContext.h>
  14. #include <LibWeb/WebIDL/DOMException.h>
  15. namespace Web::WebAudio {
  16. JS_DEFINE_ALLOCATOR(AudioBuffer);
  17. WebIDL::ExceptionOr<JS::NonnullGCPtr<AudioBuffer>> AudioBuffer::construct_impl(JS::Realm& realm, AudioBufferOptions const& options)
  18. {
  19. auto& vm = realm.vm();
  20. // 1. If any of the values in options lie outside its nominal range, throw a NotSupportedError exception and abort the following steps.
  21. TRY(BaseAudioContext::verify_audio_options_inside_nominal_range(realm, options.number_of_channels, options.length, options.sample_rate));
  22. // 2. Let b be a new AudioBuffer object.
  23. // 3. Respectively assign the values of the attributes numberOfChannels, length, sampleRate of the AudioBufferOptions passed in the
  24. // constructor to the internal slots [[number of channels]], [[length]], [[sample rate]].
  25. auto buffer = vm.heap().allocate<AudioBuffer>(realm, realm, options);
  26. // 4. Set the internal slot [[internal data]] of this AudioBuffer to the result of calling CreateByteDataBlock([[length]] * [[number of channels]]).
  27. buffer->m_channels.ensure_capacity(options.number_of_channels);
  28. for (WebIDL::UnsignedLong i = 0; i < options.number_of_channels; ++i)
  29. buffer->m_channels.unchecked_append(TRY(JS::Float32Array::create(realm, options.length)));
  30. return buffer;
  31. }
  32. AudioBuffer::~AudioBuffer() = default;
  33. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
  34. float AudioBuffer::sample_rate() const
  35. {
  36. // The sample-rate for the PCM audio data in samples per second. This MUST return the value of [[sample rate]].
  37. return m_sample_rate;
  38. }
  39. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
  40. WebIDL::UnsignedLong AudioBuffer::length() const
  41. {
  42. // Length of the PCM audio data in sample-frames. This MUST return the value of [[length]].
  43. return m_length;
  44. }
  45. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
  46. double AudioBuffer::duration() const
  47. {
  48. // Duration of the PCM audio data in seconds.
  49. // This is computed from the [[sample rate]] and the [[length]] of the AudioBuffer by performing a division between the [[length]] and the [[sample rate]].
  50. return m_length / static_cast<double>(m_sample_rate);
  51. }
  52. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
  53. WebIDL::UnsignedLong AudioBuffer::number_of_channels() const
  54. {
  55. // The number of discrete audio channels. This MUST return the value of [[number of channels]].
  56. return m_channels.size();
  57. }
  58. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
  59. WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Float32Array>> AudioBuffer::get_channel_data(WebIDL::UnsignedLong channel) const
  60. {
  61. if (channel >= m_channels.size())
  62. return WebIDL::IndexSizeError::create(realm(), "Channel index is out of range"_fly_string);
  63. return m_channels[channel];
  64. }
  65. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
  66. WebIDL::ExceptionOr<void> AudioBuffer::copy_from_channel(JS::Handle<WebIDL::BufferSource> const&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset) const
  67. {
  68. (void)channel_number;
  69. (void)buffer_offset;
  70. return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement AudioBuffer:copy_from_channel:"_fly_string);
  71. }
  72. // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
  73. WebIDL::ExceptionOr<void> AudioBuffer::copy_to_channel(JS::Handle<WebIDL::BufferSource>&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset) const
  74. {
  75. (void)channel_number;
  76. (void)buffer_offset;
  77. return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement AudioBuffer:copy_to_channel:"_fly_string);
  78. }
  79. AudioBuffer::AudioBuffer(JS::Realm& realm, AudioBufferOptions const& options)
  80. : Bindings::PlatformObject(realm)
  81. , m_length(options.length)
  82. , m_sample_rate(options.sample_rate)
  83. {
  84. }
  85. void AudioBuffer::initialize(JS::Realm& realm)
  86. {
  87. Base::initialize(realm);
  88. WEB_SET_PROTOTYPE_FOR_INTERFACE(AudioBuffer);
  89. }
  90. void AudioBuffer::visit_edges(Cell::Visitor& visitor)
  91. {
  92. Base::visit_edges(visitor);
  93. visitor.visit(m_channels);
  94. }
  95. }