Serenity Operating System
1/*
2 * Copyright (c) 2021, Cesar Torres <shortanemoia@protonmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/FixedArray.h>
10#include <AK/Forward.h>
11#include <AK/TypedTransfer.h>
12#include <LibAudio/Sample.h>
13#include <LibGUI/Frame.h>
14#include <LibGUI/Painter.h>
15
16class VisualizationWidget : public GUI::Frame {
17 C_OBJECT_ABSTRACT(VisualizationWidget)
18
19public:
20 virtual void render(GUI::PaintEvent&, FixedArray<float> const& samples) = 0;
21
22 void set_buffer(FixedArray<Audio::Sample> const& buffer)
23 {
24 if (buffer.is_empty())
25 return;
26
27 if (m_sample_buffer.size() != buffer.size())
28 m_sample_buffer.resize(buffer.size());
29
30 for (size_t i = 0; i < buffer.size(); i++)
31 m_sample_buffer.data()[i] = (buffer[i].left + buffer[i].right) / 2.f;
32
33 m_frame_count = 0;
34 }
35
36 virtual void set_samplerate(int samplerate)
37 {
38 m_samplerate = samplerate;
39 }
40
41 virtual void paint_event(GUI::PaintEvent& event) override
42 {
43 if (m_sample_buffer.size() == 0) {
44 Frame::paint_event(event);
45 GUI::Painter painter(*this);
46 painter.add_clip_rect(event.rect());
47 painter.fill_rect(frame_inner_rect(), Color::Black);
48 return;
49 }
50
51 if (m_render_buffer.size() == 0)
52 return;
53
54 size_t buffer_position = (m_frame_count * REFRESH_TIME_MILLISECONDS) * m_samplerate / 1000;
55 if (buffer_position + m_render_buffer.size() >= m_sample_buffer.size())
56 buffer_position = m_sample_buffer.size() - m_render_buffer.size();
57
58 AK::TypedTransfer<float>::copy(m_render_buffer.data(), m_sample_buffer.span().slice(buffer_position).data(), m_render_buffer.size());
59
60 render(event, m_render_buffer);
61 }
62
63 virtual void timer_event(Core::TimerEvent&) override
64 {
65 update();
66 m_frame_count++;
67 }
68
69 size_t frame_count() const { return m_frame_count; }
70
71 ErrorOr<void> set_render_sample_count(size_t count)
72 {
73 auto new_buffer = TRY(FixedArray<float>::create(count));
74 m_render_buffer.swap(new_buffer);
75 return {};
76 }
77 virtual void start_new_file(StringView) { }
78
79protected:
80 int m_samplerate;
81 size_t m_frame_count;
82 Vector<float> m_sample_buffer;
83 FixedArray<float> m_render_buffer;
84
85 static constexpr size_t REFRESH_TIME_MILLISECONDS = 30;
86
87 VisualizationWidget()
88 : m_samplerate(-1)
89 , m_frame_count(0)
90 {
91 start_timer(REFRESH_TIME_MILLISECONDS);
92 }
93
94 virtual ~VisualizationWidget() = default;
95};