42 | 42 |
}
|
43 | 43 |
|
44 | 44 |
int context::frame2pixel(double frame) {
|
45 | |
const double off = frame - playhead;
|
46 | |
const double ndc = off / (double)visrad;
|
47 | |
const int px = (int) round(width * (ndc + 1) / 2.0);
|
48 | |
if (px < 0 || px >= width) {
|
|
45 |
const double off = frame - _playhead;
|
|
46 |
const double ndc = off / (double)_visrad;
|
|
47 |
const int px = (int) round(_width * (ndc + 1) / 2.0);
|
|
48 |
if (px < 0 || px >= _width) {
|
49 | 49 |
return -1;
|
50 | 50 |
}
|
51 | 51 |
return px;
|
|
53 | 53 |
|
54 | 54 |
void context::frame(int width, int height) {
|
55 | 55 |
taskpool::get().frame();
|
56 | |
spinstep++;
|
57 | |
this->width = width;
|
58 | |
this->height = height;
|
|
56 |
_spinstep++;
|
|
57 |
_width = width;
|
|
58 |
_height = height;
|
59 | 59 |
|
60 | 60 |
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
61 | |
ImGui::SetNextWindowSize(ImVec2((float) width, (float) height));
|
|
61 |
ImGui::SetNextWindowSize(ImVec2((float) _width, (float) _height));
|
62 | 62 |
ImGui::PushStyleColor(ImGuiCol_WindowBg, qb::theme::colors[qb::theme::background]);
|
63 | 63 |
ImGui::Begin("MainWindow", nullptr,
|
64 | 64 |
ImGuiWindowFlags_NoDecoration);
|
|
70 | 70 |
maxframe = std::max(maxframe, (double) n->maxframe());
|
71 | 71 |
}
|
72 | 72 |
|
73 | |
if (!audioinit) {
|
|
73 |
if (!_audioinit) {
|
74 | 74 |
initaudio();
|
75 | 75 |
}
|
76 | |
if (audioinit) {
|
77 | |
if (ImGui::IsKeyPressed(SAPP_KEYCODE_SPACE, /* repeat */ false)) {
|
78 | |
playing = !playing;
|
79 | |
}
|
80 | |
if (!playing) {
|
81 | |
if (ImGui::IsKeyPressed(SAPP_KEYCODE_LEFT)) {
|
82 | |
playhead = floor(playhead) - 1.0;
|
83 | |
} else if (ImGui::IsKeyPressed(SAPP_KEYCODE_RIGHT)) {
|
84 | |
playhead = floor(playhead) + 1.0;
|
85 | |
} else if (ImGui::IsKeyPressed(SAPP_KEYCODE_UP)) {
|
86 | |
playhead = minframe;
|
87 | |
} else if (ImGui::IsKeyPressed(SAPP_KEYCODE_DOWN)) {
|
88 | |
playhead = maxframe;
|
89 | |
}
|
90 | |
} else {
|
91 | |
if (playhead > maxframe) {
|
92 | |
playing = false;
|
93 | |
}
|
94 | |
}
|
95 | |
pushaudio();
|
96 | |
}
|
|
76 |
|
|
77 |
if (ImGui::IsKeyPressed(SAPP_KEYCODE_SPACE, /* repeat */ false)) {
|
|
78 |
_playing = !_playing;
|
|
79 |
}
|
|
80 |
if (!_playing) {
|
|
81 |
if (ImGui::IsKeyPressed(SAPP_KEYCODE_LEFT)) {
|
|
82 |
_playhead = floor(_playhead) - 1.0;
|
|
83 |
} else if (ImGui::IsKeyPressed(SAPP_KEYCODE_RIGHT)) {
|
|
84 |
_playhead = floor(_playhead) + 1.0;
|
|
85 |
} else if (ImGui::IsKeyPressed(SAPP_KEYCODE_UP)) {
|
|
86 |
_playhead = minframe;
|
|
87 |
} else if (ImGui::IsKeyPressed(SAPP_KEYCODE_DOWN)) {
|
|
88 |
_playhead = maxframe;
|
|
89 |
}
|
|
90 |
} else {
|
|
91 |
if (_playhead > maxframe) {
|
|
92 |
_playing = false;
|
|
93 |
}
|
|
94 |
}
|
|
95 |
pushaudio();
|
97 | 96 |
|
98 | 97 |
if (ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) {
|
99 | 98 |
const ImVec2 delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle);
|
100 | |
const bool horiz = !playing && abs(delta.x) > abs(delta.y);
|
101 | |
const double pxperframe = width / (2.0 * std::max(visrad, 1.0));
|
|
99 |
const bool horiz = !_playing && abs(delta.x) > abs(delta.y);
|
|
100 |
const double pxperframe = _width / (2.0 * std::max(_visrad, 1.0));
|
102 | 101 |
const double framedist = horiz ? 0.1 * delta.x / pxperframe : 0;
|
103 | 102 |
const double zoomdist = !horiz ? 0.1 * delta.y / pxperframe : 0;
|
104 | |
playhead = clamp((double)playhead + framedist, minframe, maxframe);
|
105 | |
visrad = clamp((double)visrad + zoomdist, 3.0, maxframe - minframe);
|
106 | |
}
|
107 | |
|
108 | |
// draw playhead
|
|
103 |
_playhead = clamp((double)_playhead + framedist, minframe, maxframe);
|
|
104 |
_visrad = clamp((double)_visrad + zoomdist, 3.0, maxframe - minframe);
|
|
105 |
}
|
|
106 |
if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
|
|
107 |
const ImVec2 delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left);
|
|
108 |
|
|
109 |
}
|
|
110 |
|
|
111 |
// draw _playhead
|
109 | 112 |
{
|
110 | 113 |
ImDrawList * const drawlist = ImGui::GetWindowDrawList();
|
111 | |
const float f0x = (float) frame2pixel(playhead);
|
112 | |
const float f1x = (float) frame2pixel(playhead + 1);
|
|
114 |
const float f0x = (float) frame2pixel(_playhead);
|
|
115 |
const float f1x = (float) frame2pixel(_playhead + 1);
|
113 | 116 |
if (f1x > 0 && f1x != f0x) {
|
114 | |
drawlist->AddRectFilled(ImVec2(f0x, 0.0), ImVec2(f1x, (float) height),
|
|
117 |
drawlist->AddRectFilled(ImVec2(f0x, 0.0), ImVec2(f1x, (float) _height),
|
115 | 118 |
qb::theme::colors[qb::theme::color::playhead]);
|
116 | 119 |
} else {
|
117 | |
drawlist->AddLine(ImVec2(f0x, 0), ImVec2(f0x, (float) height),
|
|
120 |
drawlist->AddLine(ImVec2(f0x, 0), ImVec2(f0x, (float) _height),
|
118 | 121 |
qb::theme::colors[qb::theme::color::playhead]);
|
119 | 122 |
}
|
120 | 123 |
}
|
|
145 | 148 |
if (!audio) {
|
146 | 149 |
return;
|
147 | 150 |
}
|
148 | |
|
149 | |
saudio_desc d = {0};
|
|
151 |
_audiosource = audio;
|
|
152 |
|
|
153 |
saudio_desc d;
|
150 | 154 |
d.sample_rate = audio->data()->getSampleRate();
|
151 | 155 |
d.num_channels = audio->data()->getNumChannels();
|
|
156 |
d.buffer_frames = 0;
|
|
157 |
d.packet_frames = 0;
|
|
158 |
d.num_packets = 0;
|
|
159 |
d.stream_cb = nullptr;
|
|
160 |
d.stream_userdata_cb = nullptr;
|
|
161 |
d.user_data = nullptr;
|
152 | 162 |
|
153 | 163 |
saudio_setup(&d);
|
154 | |
audioinit = saudio_isvalid();
|
155 | |
if (!audioinit) {
|
156 | |
ImGui::Text("could not initialize audio engine");
|
157 | |
} else {
|
158 | |
audiosource = audio;
|
|
164 |
_audioinit = saudio_isvalid();
|
|
165 |
if (!_audioinit) {
|
|
166 |
ImGui::Text(
|
|
167 |
"could not initialize audio engine (rate=%d, channels=%d)",
|
|
168 |
d.sample_rate, d.num_channels);
|
159 | 169 |
}
|
160 | 170 |
}
|
161 | 171 |
|
162 | 172 |
void context::pushaudio() {
|
163 | |
if (!audiosource) {
|
|
173 |
if (!_audioinit or !_audiosource) {
|
|
174 |
if (_playing) {
|
|
175 |
const double elapsed = ImGui::GetIO().DeltaTime;
|
|
176 |
_playhead += elapsed * _framerate;
|
|
177 |
}
|
164 | 178 |
return;
|
165 | 179 |
}
|
166 | 180 |
|
167 | |
const audio_node *audio = static_cast<const audio_node*>(audiosource);
|
|
181 |
const audio_node *audio = static_cast<const audio_node*>(_audiosource);
|
168 | 182 |
const int samplerate = audio->data()->getSampleRate();
|
169 | 183 |
const double sampleperframe = (double) samplerate / (double) _framerate;
|
170 | 184 |
const std::vector<float> &s = audio->packed();
|
171 | 185 |
|
172 | |
if (!playing) {
|
173 | |
if ((int) playhead == playedframe) {
|
|
186 |
if (!_playing) {
|
|
187 |
if ((int) _playhead == _playedframe) {
|
174 | 188 |
return;
|
175 | 189 |
}
|
176 | |
const double firstsample = floor(playhead) * sampleperframe;
|
|
190 |
const double firstsample = floor(_playhead) * sampleperframe;
|
177 | 191 |
const size_t s0 = (size_t) floor(firstsample);
|
178 | 192 |
if (s0 >= s.size()) {
|
179 | 193 |
return;
|
180 | 194 |
}
|
181 | 195 |
const int topush = std::min((int) sampleperframe, (int) (s.size() - s0));
|
182 | 196 |
const int pushed = saudio_push(&s[s0], topush);
|
183 | |
playedframe = (int) playhead;
|
184 | |
pushedsample = (int64_t) (s0 + sampleperframe - 1);
|
|
197 |
_playedframe = (int) _playhead;
|
|
198 |
_pushedsample = (int64_t) (s0 + sampleperframe - 1);
|
185 | 199 |
|
186 | 200 |
} else {
|
187 | 201 |
const double elapsed = ImGui::GetIO().DeltaTime;
|
188 | |
playhead += elapsed * _framerate;
|
189 | |
|
190 | |
const int64_t nextsample = (int64_t) floor(playhead * sampleperframe);
|
|
202 |
_playhead += elapsed * _framerate;
|
|
203 |
|
|
204 |
const int64_t nextsample = (int64_t) floor(_playhead * sampleperframe);
|
191 | 205 |
|
192 | 206 |
// buffer 125ms of audio
|
193 | 207 |
const int64_t buffersamples = samplerate / 8;
|
|
195 | 209 |
const int64_t bufferrefill = samplerate / 20;
|
196 | 210 |
|
197 | 211 |
int64_t fillfrom = -1;
|
198 | |
int64_t dist = pushedsample - nextsample;
|
199 | |
if (pushedsample < 0) {
|
|
212 |
int64_t dist = _pushedsample - nextsample;
|
|
213 |
if (_pushedsample < 0) {
|
200 | 214 |
fillfrom = nextsample;
|
201 | 215 |
} else if (dist < bufferrefill) {
|
202 | |
fillfrom = pushedsample + 1;
|
|
216 |
fillfrom = _pushedsample + 1;
|
203 | 217 |
}
|
204 | 218 |
|
205 | 219 |
if (fillfrom >= 0 && (size_t) fillfrom < s.size()) {
|
206 | 220 |
const int fillamount =
|
207 | 221 |
(int) std::min(buffersamples, (int64_t)(s.size() - fillfrom - 1));
|
208 | 222 |
const int pushed = saudio_push(&s[fillfrom], fillamount);
|
209 | |
pushedsample = fillfrom + pushed;
|
|
223 |
_pushedsample = fillfrom + pushed;
|
210 | 224 |
}
|
211 | 225 |
}
|
212 | 226 |
}
|