BaseAudioContext.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
  3. * Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibWeb/Bindings/BaseAudioContextPrototype.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/HTML/EventNames.h>
  10. #include <LibWeb/WebAudio/AudioBuffer.h>
  11. #include <LibWeb/WebAudio/AudioBufferSourceNode.h>
  12. #include <LibWeb/WebAudio/AudioDestinationNode.h>
  13. #include <LibWeb/WebAudio/BaseAudioContext.h>
  14. #include <LibWeb/WebAudio/BiquadFilterNode.h>
  15. #include <LibWeb/WebAudio/DynamicsCompressorNode.h>
  16. #include <LibWeb/WebAudio/GainNode.h>
  17. #include <LibWeb/WebAudio/OscillatorNode.h>
  18. namespace Web::WebAudio {
  19. BaseAudioContext::BaseAudioContext(JS::Realm& realm, float sample_rate)
  20. : DOM::EventTarget(realm)
  21. , m_sample_rate(sample_rate)
  22. {
  23. }
  24. BaseAudioContext::~BaseAudioContext() = default;
  25. void BaseAudioContext::initialize(JS::Realm& realm)
  26. {
  27. Base::initialize(realm);
  28. WEB_SET_PROTOTYPE_FOR_INTERFACE(BaseAudioContext);
  29. }
  30. void BaseAudioContext::visit_edges(Cell::Visitor& visitor)
  31. {
  32. Base::visit_edges(visitor);
  33. visitor.visit(m_destination);
  34. }
  35. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
  36. JS::NonnullGCPtr<AudioDestinationNode> BaseAudioContext::destination()
  37. {
  38. auto& realm = this->realm();
  39. dbgln("FIXME: Properly implement BaseAudioContext::destination");
  40. if (!m_destination)
  41. m_destination = realm.heap().allocate<AudioDestinationNode>(realm, realm, *this);
  42. return *m_destination;
  43. }
  44. void BaseAudioContext::set_onstatechange(WebIDL::CallbackType* event_handler)
  45. {
  46. set_event_handler_attribute(HTML::EventNames::statechange, event_handler);
  47. }
  48. WebIDL::CallbackType* BaseAudioContext::onstatechange()
  49. {
  50. return event_handler_attribute(HTML::EventNames::statechange);
  51. }
  52. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbiquadfilter
  53. WebIDL::ExceptionOr<JS::NonnullGCPtr<BiquadFilterNode>> BaseAudioContext::create_biquad_filter()
  54. {
  55. // Factory method for a BiquadFilterNode representing a second order filter which can be configured as one of several common filter types.
  56. return BiquadFilterNode::create(realm(), *this);
  57. }
  58. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
  59. WebIDL::ExceptionOr<JS::NonnullGCPtr<AudioBuffer>> BaseAudioContext::create_buffer(WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate)
  60. {
  61. // Creates an AudioBuffer of the given size. The audio data in the buffer will be zero-initialized (silent).
  62. // A NotSupportedError exception MUST be thrown if any of the arguments is negative, zero, or outside its nominal range.
  63. return AudioBuffer::create(realm(), number_of_channels, length, sample_rate);
  64. }
  65. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffersource
  66. WebIDL::ExceptionOr<JS::NonnullGCPtr<AudioBufferSourceNode>> BaseAudioContext::create_buffer_source()
  67. {
  68. // Factory method for a AudioBufferSourceNode.
  69. return AudioBufferSourceNode::create(realm(), *this);
  70. }
  71. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createoscillator
  72. WebIDL::ExceptionOr<JS::NonnullGCPtr<OscillatorNode>> BaseAudioContext::create_oscillator()
  73. {
  74. // Factory method for an OscillatorNode.
  75. return OscillatorNode::create(realm(), *this);
  76. }
  77. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createdynamicscompressor
  78. WebIDL::ExceptionOr<JS::NonnullGCPtr<DynamicsCompressorNode>> BaseAudioContext::create_dynamics_compressor()
  79. {
  80. // Factory method for a DynamicsCompressorNode.
  81. return DynamicsCompressorNode::create(realm(), *this);
  82. }
  83. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-creategain
  84. JS::NonnullGCPtr<GainNode> BaseAudioContext::create_gain()
  85. {
  86. // Factory method for GainNode.
  87. return GainNode::create(realm(), *this);
  88. }
  89. // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
  90. WebIDL::ExceptionOr<void> BaseAudioContext::verify_audio_options_inside_nominal_range(JS::Realm& realm, WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate)
  91. {
  92. // A NotSupportedError exception MUST be thrown if any of the arguments is negative, zero, or outside its nominal range.
  93. if (number_of_channels == 0)
  94. return WebIDL::NotSupportedError::create(realm, "Number of channels must not be '0'"_fly_string);
  95. if (number_of_channels > MAX_NUMBER_OF_CHANNELS)
  96. return WebIDL::NotSupportedError::create(realm, "Number of channels is greater than allowed range"_fly_string);
  97. if (length == 0)
  98. return WebIDL::NotSupportedError::create(realm, "Length of buffer must be at least 1"_fly_string);
  99. if (sample_rate < MIN_SAMPLE_RATE || sample_rate > MAX_SAMPLE_RATE)
  100. return WebIDL::NotSupportedError::create(realm, "Sample rate is outside of allowed range"_fly_string);
  101. return {};
  102. }
  103. }