11 | 11 |
|
12 | 12 |
void context::frame(int width, int height) {
|
13 | 13 |
taskpool::get().frame();
|
|
14 |
spinstep++;
|
14 | 15 |
|
15 | 16 |
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
16 | 17 |
ImGui::SetNextWindowSize(ImVec2((float) width, (float) height));
|
17 | 18 |
ImGui::Begin("MainWindow", nullptr, ImGuiWindowFlags_NoDecoration);
|
18 | |
ImGui::Text("%d nodes in context", _nodes.size());
|
|
19 |
|
|
20 |
int minframe = 0, maxframe = 0;
|
|
21 |
for (const auto &n : _nodes) {
|
|
22 |
minframe = std::min(minframe, n->minframe());
|
|
23 |
maxframe = std::max(maxframe, n->maxframe());
|
|
24 |
}
|
|
25 |
ImGui::DragIntRange2("visible", &vismin, &vismax, 1.0, minframe, maxframe);
|
|
26 |
|
19 | 27 |
for (const auto &n : _nodes) {
|
20 | 28 |
draw_node(n);
|
21 | 29 |
}
|
22 | 30 |
ImGui::End();
|
|
31 |
|
|
32 |
ImGui::ShowDemoWindow();
|
23 | 33 |
}
|
24 | 34 |
|
25 | 35 |
void context::shutdown() {
|
|
36 | 46 |
taskpool::get().submit_async([this]() { this->load_async(); });
|
37 | 47 |
}
|
38 | 48 |
|
|
49 |
static constexpr double render_rate_hi = 8;
|
|
50 |
static constexpr double render_rate_lo = 2;
|
|
51 |
static constexpr int hires_frame_limit = 1000;
|
|
52 |
|
|
53 |
const std::vector<float>& audio_node::rendered() const {
|
|
54 |
int visframes = _c->vismax - _c->vismin;
|
|
55 |
return visframes > hires_frame_limit ? _rlo : _rhi;
|
|
56 |
}
|
|
57 |
|
|
58 |
double audio_node::rsamplerate() const {
|
|
59 |
int visframes = _c->vismax - _c->vismin;
|
|
60 |
return (visframes > hires_frame_limit ? render_rate_lo : render_rate_hi);
|
|
61 |
}
|
|
62 |
|
39 | 63 |
void audio_node::load_async() {
|
40 | 64 |
taskpool::get().submit_frame([this]() {
|
41 | 65 |
this->_loadstate = load_state(load_state::loading, "loading file");
|
|
50 | 74 |
}
|
51 | 75 |
|
52 | 76 |
taskpool::get().submit_frame([this]() {
|
53 | |
this->_loadstate = load_state(load_state::loading, "generating preview");
|
|
77 |
this->_loadstate =
|
|
78 |
load_state(load_state::loading, "generating hi-res preview");
|
54 | 79 |
});
|
55 | |
render_samples();
|
|
80 |
_rhi = render_samples(render_rate_hi);
|
|
81 |
|
|
82 |
taskpool::get().submit_frame([this]() {
|
|
83 |
this->_loadstate =
|
|
84 |
load_state(load_state::loading, "generating lo-res preview");
|
|
85 |
});
|
|
86 |
_rlo = render_samples(render_rate_lo);
|
56 | 87 |
|
57 | 88 |
// update load state on main thread: this is what governs whether the UI
|
58 | 89 |
// accesses the rest of the state here or not.
|
|
61 | 92 |
});
|
62 | 93 |
}
|
63 | 94 |
|
64 | |
void audio_node::render_samples() {
|
|
95 |
std::vector<float> audio_node::render_samples(double framesamples) {
|
65 | 96 |
const size_t samples = _data->getNumSamplesPerChannel();
|
66 | |
const double framerate = _c->framerate();
|
67 | |
|
68 | |
const double spf = (double)_data->getSampleRate() / framerate;
|
69 | |
const int frames = 8 * (int) ceil(samples / spf);
|
|
97 |
const double spr =
|
|
98 |
(double)_data->getSampleRate() / (framesamples * _c->framerate());
|
|
99 |
const size_t rsamples = ceil((double)samples / spr);
|
70 | 100 |
const int channels = _data->getNumChannels();
|
71 | 101 |
|
72 | |
_rendered.resize(frames);
|
73 | |
for (int i = 0; i < frames; i++) {
|
74 | |
const double s1 = i * spf;
|
75 | |
const double s2 = (i + 1) * spf;
|
76 | |
float sum = 0;
|
|
102 |
std::vector<float> rendered;
|
|
103 |
rendered.resize(rsamples);
|
|
104 |
float absmax = 0;
|
|
105 |
for (int i = 0; i < rsamples; i++) {
|
|
106 |
const double s1 = i * spr;
|
|
107 |
const double s2 = (i + 1) * spr;
|
|
108 |
double sum = 0;
|
77 | 109 |
for (int chan = 0; chan < channels; chan++) {
|
78 | |
for (size_t s = (size_t)floor(s1); s < (size_t)ceil(s2); s++) {
|
79 | |
const float sample = s >= samples ? 0 : _data->samples[chan][s];
|
80 | |
if (s == floor(s1) && (double)s != s1) {
|
81 | |
sum += sample * (ceil(s1) - s1);
|
82 | |
} else if (s == ceil(s2) && (double)s != s2) {
|
83 | |
sum += sample * (s2 - floor(s2));
|
84 | |
} else {
|
85 | |
sum += sample;
|
86 | |
}
|
|
110 |
for (size_t s = (size_t)floor(s1);
|
|
111 |
s < (size_t)ceil(s2) && s < _data->samples[chan].size();
|
|
112 |
s++) {
|
|
113 |
double x = _data->samples[chan][s];
|
|
114 |
sum += (x < 0 ? -1.0 : 1.0) * sqrt(fabs(x));
|
87 | 115 |
}
|
88 | 116 |
}
|
89 | |
_rendered[i] = (float)(sum / (spf * (double)channels));
|
|
117 |
const float r = (float) (sum / (spr * channels));
|
|
118 |
absmax = std::max(absmax, fabsf(r));
|
|
119 |
rendered[i] = r;
|
90 | 120 |
}
|
|
121 |
for (float &f : rendered) {
|
|
122 |
f /= absmax;
|
|
123 |
}
|
|
124 |
return rendered;
|
|
125 |
}
|
|
126 |
|
|
127 |
int audio_node::minframe() const {
|
|
128 |
return 0;
|
|
129 |
}
|
|
130 |
|
|
131 |
int audio_node::maxframe() const {
|
|
132 |
if (_loadstate.stage != load_state::loaded) {
|
|
133 |
return 0;
|
|
134 |
}
|
|
135 |
return (int) ceil(_data->getLengthInSeconds() * _c->framerate());
|
91 | 136 |
}
|
92 | 137 |
|
93 | 138 |
audio_node::~audio_node() = default;
|