cubeb_resampler_speex::cubeb_resampler_speex(SpeexResamplerState * r, cubeb_stream * s, cubeb_stream_params params, uint32_t out_rate, cubeb_data_callback cb, long max_count, void * ptr) : speex_resampler(r) , stream(s) , stream_params(params) , data_callback(cb) , user_ptr(ptr) , buffer_frame_count(max_count) , resampling_ratio(static_cast<float>(params.rate) / out_rate) , leftover_frame_size(static_cast<uint32_t>(ceilf(1 / resampling_ratio * 2) + 1)) , leftover_frame_count(0) { leftover_frames_buffer = new uint8_t[frames_to_bytes(params, leftover_frame_size)]; size_t frames_needed = frame_count_at_rate(buffer_frame_count, resampling_ratio); resampling_src_buffer = new uint8_t[frames_to_bytes(params, frames_needed)]; assert(r); assert(leftover_frames_buffer); assert(resampling_src_buffer); }
long cubeb_resampler_speex::fill(void * input_buffer, void * output_buffer, long frames_needed) { // Use more input frames than strictly necessary, so in the worst case, // we have leftover unresampled frames at the end, that we can use // during the next iteration. assert(frames_needed <= buffer_frame_count); long before_resampling = frame_count_at_rate(frames_needed, resampling_ratio); long frames_requested = before_resampling - leftover_frame_count; // Copy the previous leftover frames to the front of the buffer. size_t leftover_bytes = frames_to_bytes(stream_params, leftover_frame_count); memcpy(resampling_src_buffer.get(), leftover_frames_buffer.get(), leftover_bytes); uint8_t * buffer_start = resampling_src_buffer.get() + leftover_bytes; long got = data_callback(stream, user_ptr, NULL, buffer_start, frames_requested); assert(got <= frames_requested); if (got < 0) { return CUBEB_ERROR; } uint32_t in_frames = leftover_frame_count + got; uint32_t out_frames = frames_needed; uint32_t old_in_frames = in_frames; if (stream_params.format == CUBEB_SAMPLE_FLOAT32NE) { float * in_buffer = reinterpret_cast<float *>(resampling_src_buffer.get()); float * out_buffer = reinterpret_cast<float *>(output_buffer); speex_resampler_process_interleaved_float(speex_resampler, in_buffer, &in_frames, out_buffer, &out_frames); } else { short * in_buffer = reinterpret_cast<short *>(resampling_src_buffer.get()); short * out_buffer = reinterpret_cast<short *>(output_buffer); speex_resampler_process_interleaved_int(speex_resampler, in_buffer, &in_frames, out_buffer, &out_frames); } // Copy the leftover frames to buffer for the next time. leftover_frame_count = old_in_frames - in_frames; assert(leftover_frame_count <= leftover_frame_size); size_t unresampled_bytes = frames_to_bytes(stream_params, leftover_frame_count); uint8_t * leftover_frames_start = resampling_src_buffer.get(); leftover_frames_start += frames_to_bytes(stream_params, in_frames); memcpy(leftover_frames_buffer.get(), leftover_frames_start, unresampled_bytes); return out_frames; }