MCPcopy Create free account
hub / github.com/RevoSucks/BM64Recomp / queue_samples

Function queue_samples

src/main/main.cpp:202–265  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

200constexpr uint32_t bytes_per_frame = input_channels * sizeof(float);
201
202void queue_samples(int16_t* audio_data, size_t sample_count) {
203 // Buffer for holding the output of swapping the audio channels. This is reused across
204 // calls to reduce runtime allocations.
205 static std::vector<float> swap_buffer;
206 static std::array<float, duplicated_input_frames * input_channels> duplicated_sample_buffer;
207
208 // Make sure the swap buffer is large enough to hold the audio data, including any extra space needed for resampling.
209 size_t resampled_sample_count = sample_count + duplicated_input_frames * input_channels;
210 size_t max_sample_count = std::max(resampled_sample_count, resampled_sample_count * audio_convert.len_mult);
211 if (max_sample_count > swap_buffer.size()) {
212 swap_buffer.resize(max_sample_count);
213 }
214
215 // Copy the duplicated frames from last chunk into this chunk
216 for (size_t i = 0; i < duplicated_input_frames * input_channels; i++) {
217 swap_buffer[i] = duplicated_sample_buffer[i];
218 }
219
220 // Convert the audio from 16-bit values to floats and swap the audio channels into the
221 // swap buffer to correct for the address xor caused by endianness handling.
222 float cur_main_volume = zelda64::get_main_volume() / 100.0f; // Get the current main volume, normalized to 0.0-1.0.
223 for (size_t i = 0; i < sample_count; i += input_channels) {
224 swap_buffer[i + 0 + duplicated_input_frames * input_channels] = audio_data[i + 1] * (1.0f / 32768.0f) * cur_main_volume;
225 swap_buffer[i + 1 + duplicated_input_frames * input_channels] = audio_data[i + 0] * (1.0f / 32768.0f) * cur_main_volume;
226 }
227
228 // TODO handle cases where a chunk is smaller than the duplicated frame count.
229 assert(sample_count > duplicated_input_frames * input_channels);
230
231 // Copy the last converted samples into the duplicated sample buffer to reuse in resampling the next queued chunk.
232 for (size_t i = 0; i < duplicated_input_frames * input_channels; i++) {
233 duplicated_sample_buffer[i] = swap_buffer[i + sample_count];
234 }
235
236 audio_convert.buf = reinterpret_cast<Uint8*>(swap_buffer.data());
237 audio_convert.len = (sample_count + duplicated_input_frames * input_channels) * sizeof(swap_buffer[0]);
238
239 int ret = SDL_ConvertAudio(&audio_convert);
240
241 if (ret < 0) {
242 printf("Error using SDL audio converter: %s\n", SDL_GetError());
243 throw std::runtime_error("Error using SDL audio converter");
244 }
245
246 uint64_t cur_queued_microseconds = uint64_t(SDL_GetQueuedAudioSize(audio_device)) / bytes_per_frame * 1000000 / sample_rate;
247 uint32_t num_bytes_to_queue = audio_convert.len_cvt - output_channels * discarded_output_frames * sizeof(swap_buffer[0]);
248 float* samples_to_queue = swap_buffer.data() + output_channels * discarded_output_frames / 2;
249
250 // Prevent audio latency from building up by skipping samples in incoming audio when too many samples are already queued.
251 // Skip samples based on how many microseconds of samples are queued already.
252 uint32_t skip_factor = cur_queued_microseconds / 100000;
253 if (skip_factor != 0) {
254 uint32_t skip_ratio = 1 << skip_factor;
255 num_bytes_to_queue /= skip_ratio;
256 for (size_t i = 0; i < num_bytes_to_queue / (output_channels * sizeof(swap_buffer[0])); i++) {
257 samples_to_queue[2 * i + 0] = samples_to_queue[2 * skip_ratio * i + 0];
258 samples_to_queue[2 * i + 1] = samples_to_queue[2 * skip_ratio * i + 1];
259 }

Callers

nothing calls this directly

Calls 1

sizeMethod · 0.45

Tested by

no test coverage detected