22 | 22 |
qb::theme::setdefault();
|
23 | 23 |
}
|
24 | 24 |
|
25 | |
int context::frame2pixel(int frame) {
|
|
25 |
int context::frame2pixel(double frame) {
|
26 | 26 |
const double off = frame - playhead;
|
27 | 27 |
const double ndc = off / (double)visrad;
|
28 | 28 |
const int px = (int) round(width * (ndc + 1) / 2.0);
|
|
48 | 48 |
initaudio();
|
49 | 49 |
}
|
50 | 50 |
if (audioinit) {
|
|
51 |
if (ImGui::IsKeyPressed(SAPP_KEYCODE_SPACE, /* repeat */ false)) {
|
|
52 |
playing = !playing;
|
|
53 |
}
|
51 | 54 |
pushaudio();
|
52 | 55 |
}
|
53 | 56 |
|
|
60 | 63 |
|
61 | 64 |
if (ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) {
|
62 | 65 |
const ImVec2 delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle);
|
63 | |
const bool horiz = abs(delta.x) > abs(delta.y);
|
|
66 |
const bool horiz = !playing && abs(delta.x) > abs(delta.y);
|
64 | 67 |
const double pxperframe = width / (2.0 * std::max(visrad, 1.0));
|
65 | 68 |
const double framedist = horiz ? 0.1 * delta.x / pxperframe : 0;
|
66 | 69 |
const double zoomdist = !horiz ? 0.1 * delta.y / pxperframe : 0;
|
|
71 | 74 |
// draw playhead
|
72 | 75 |
{
|
73 | 76 |
ImDrawList * const drawlist = ImGui::GetWindowDrawList();
|
74 | |
const float f0x = (float) frame2pixel((int) playhead);
|
75 | |
const float f1x = (float) frame2pixel((int) playhead + 1);
|
|
77 |
const float f0x = (float) frame2pixel(playhead);
|
|
78 |
const float f1x = (float) frame2pixel(playhead + 1);
|
76 | 79 |
if (f1x > 0 && f1x != f0x) {
|
77 | 80 |
drawlist->AddRectFilled(ImVec2(f0x, 0.0), ImVec2(f1x, (float) height),
|
78 | 81 |
qb::theme::colors[qb::theme::color::playhead]);
|
|
111 | 114 |
saudio_desc d = {0};
|
112 | 115 |
d.sample_rate = audiosource->data()->getSampleRate();
|
113 | 116 |
d.num_channels = audiosource->data()->getNumChannels();
|
114 | |
//d.buffer_frames = 4 * d.sample_rate / _framerate;
|
115 | 117 |
|
116 | 118 |
saudio_setup(&d);
|
117 | 119 |
audioinit = saudio_isvalid();
|
|
125 | 127 |
if (!audiosource) {
|
126 | 128 |
return;
|
127 | 129 |
}
|
|
130 |
|
|
131 |
const int samplerate = audiosource->data()->getSampleRate();
|
|
132 |
const double sampleperframe = (double) samplerate / (double) _framerate;
|
|
133 |
|
128 | 134 |
if (!playing) {
|
129 | 135 |
if ((int) playhead == playedframe) {
|
130 | 136 |
return;
|
131 | 137 |
}
|
132 | |
const int samplerate = audiosource->data()->getSampleRate();
|
133 | |
const double sampleperframe = (double) samplerate / (double) _framerate;
|
134 | 138 |
const double firstsample = floor(playhead) * sampleperframe;
|
135 | 139 |
const size_t s0 = (size_t) floor(firstsample);
|
136 | 140 |
|
137 | 141 |
const int topush = (int) sampleperframe;
|
138 | 142 |
const int pushed =
|
139 | 143 |
saudio_push(&audiosource->packed()[s0], topush);
|
140 | |
if (pushed != topush) {
|
141 | |
printf("tried to push %d at offset %zu, pushed %d\n", topush, s0, pushed);
|
142 | |
}
|
143 | 144 |
playedframe = (int) playhead;
|
|
145 |
pushedsample = (int64_t) (s0 + sampleperframe - 1);
|
|
146 |
|
|
147 |
} else {
|
|
148 |
|
|
149 |
const double elapsed = ImGui::GetIO().DeltaTime;
|
|
150 |
playhead += elapsed * _framerate;
|
|
151 |
|
|
152 |
const int64_t nextsample = (int64_t) floor(playhead * sampleperframe);
|
|
153 |
|
|
154 |
// buffer 125ms of audio
|
|
155 |
const int buffersamples = samplerate / 8;
|
|
156 |
// add to buffer whenever we have less than 50ms left in the buffer
|
|
157 |
const int bufferrefill = samplerate / 20;
|
|
158 |
|
|
159 |
if (pushedsample < 0) {
|
|
160 |
int pushed = saudio_push(&audiosource->packed()[nextsample], buffersamples);
|
|
161 |
pushedsample = nextsample + pushed;
|
|
162 |
} else if (pushedsample - nextsample < bufferrefill) {
|
|
163 |
int pushed = saudio_push(&audiosource->packed()[pushedsample + 1], buffersamples);
|
|
164 |
pushedsample += pushed;
|
|
165 |
}
|
144 | 166 |
}
|
145 | 167 |
}
|
146 | 168 |
|