duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

cubeb_resampler.cpp (13098B)


      1 /*
      2  * Copyright © 2014 Mozilla Foundation
      3  *
      4  * This program is made available under an ISC-style license.  See the
      5  * accompanying file LICENSE for details.
      6  */
      7 #ifndef NOMINMAX
      8 #define NOMINMAX
      9 #endif // NOMINMAX
     10 
     11 #include "cubeb_resampler.h"
     12 #include "cubeb-speex-resampler.h"
     13 #include "cubeb_resampler_internal.h"
     14 #include "cubeb_utils.h"
     15 #include <algorithm>
     16 #include <cassert>
     17 #include <cmath>
     18 #include <cstddef>
     19 #include <cstdio>
     20 #include <cstring>
     21 
     22 int
     23 to_speex_quality(cubeb_resampler_quality q)
     24 {
     25   switch (q) {
     26   case CUBEB_RESAMPLER_QUALITY_VOIP:
     27     return SPEEX_RESAMPLER_QUALITY_VOIP;
     28   case CUBEB_RESAMPLER_QUALITY_DEFAULT:
     29     return SPEEX_RESAMPLER_QUALITY_DEFAULT;
     30   case CUBEB_RESAMPLER_QUALITY_DESKTOP:
     31     return SPEEX_RESAMPLER_QUALITY_DESKTOP;
     32   default:
     33     assert(false);
     34     return 0XFFFFFFFF;
     35   }
     36 }
     37 
     38 uint32_t
     39 min_buffered_audio_frame(uint32_t sample_rate)
     40 {
     41   return sample_rate / 20;
     42 }
     43 
     44 template <typename T>
     45 passthrough_resampler<T>::passthrough_resampler(cubeb_stream * s,
     46                                                 cubeb_data_callback cb,
     47                                                 void * ptr,
     48                                                 uint32_t input_channels,
     49                                                 uint32_t sample_rate)
     50     : processor(input_channels), stream(s), data_callback(cb), user_ptr(ptr),
     51       sample_rate(sample_rate)
     52 {
     53 }
     54 
     55 template <typename T>
     56 long
     57 passthrough_resampler<T>::fill(void * input_buffer, long * input_frames_count,
     58                                void * output_buffer, long output_frames)
     59 {
     60   if (input_buffer) {
     61     assert(input_frames_count);
     62   }
     63   assert((input_buffer && output_buffer) ||
     64          (output_buffer && !input_buffer &&
     65           (!input_frames_count || *input_frames_count == 0)) ||
     66          (input_buffer && !output_buffer && output_frames == 0));
     67 
     68   // When we have no pending input data and exactly as much input
     69   // as output data, we don't need to copy it into the internal buffer
     70   // and can directly forward it to the callback.
     71   void * in_buf = input_buffer;
     72   unsigned long pop_input_count = 0u;
     73   if (input_buffer && !output_buffer) {
     74     output_frames = *input_frames_count;
     75   } else if (input_buffer) {
     76     if (internal_input_buffer.length() != 0 ||
     77         *input_frames_count < output_frames) {
     78       // If we have pending input data left and have to first append the input
     79       // so we can pass it as one pointer to the callback. Or this is a glitch.
     80       // It can happen when system's performance is poor. Audible silence is
     81       // being pushed at the end of the short input buffer. An improvement for
     82       // the future is to resample to the output number of frames, when that
     83       // happens.
     84       internal_input_buffer.push(static_cast<T *>(input_buffer),
     85                                  frames_to_samples(*input_frames_count));
     86       if (internal_input_buffer.length() < frames_to_samples(output_frames)) {
     87         // This is unxpected but it can happen when a glitch occurs. Fill the
     88         // buffer with silence. First keep the actual number of input samples
     89         // used without the silence.
     90         pop_input_count = internal_input_buffer.length();
     91         internal_input_buffer.push_silence(frames_to_samples(output_frames) -
     92                                            internal_input_buffer.length());
     93       } else {
     94         pop_input_count = frames_to_samples(output_frames);
     95       }
     96       in_buf = internal_input_buffer.data();
     97     } else if (*input_frames_count > output_frames) {
     98       // In this case we have more input that we need output and
     99       // fill the overflowing input into internal_input_buffer
    100       // Since we have no other pending data, we can nonetheless
    101       // pass the current input data directly to the callback
    102       assert(pop_input_count == 0);
    103       unsigned long samples_off = frames_to_samples(output_frames);
    104       internal_input_buffer.push(
    105           static_cast<T *>(input_buffer) + samples_off,
    106           frames_to_samples(*input_frames_count - output_frames));
    107     }
    108   }
    109 
    110   long rv =
    111       data_callback(stream, user_ptr, in_buf, output_buffer, output_frames);
    112 
    113   if (input_buffer) {
    114     if (pop_input_count) {
    115       internal_input_buffer.pop(nullptr, pop_input_count);
    116       *input_frames_count = samples_to_frames(pop_input_count);
    117     } else {
    118       *input_frames_count = output_frames;
    119     }
    120     drop_audio_if_needed();
    121   }
    122 
    123   return rv;
    124 }
    125 
    126 // Explicit instantiation of template class.
    127 template class passthrough_resampler<float>;
    128 template class passthrough_resampler<short>;
    129 
    130 template <typename T, typename InputProcessor, typename OutputProcessor>
    131 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::
    132     cubeb_resampler_speex(InputProcessor * input_processor,
    133                           OutputProcessor * output_processor, cubeb_stream * s,
    134                           cubeb_data_callback cb, void * ptr)
    135     : input_processor(input_processor), output_processor(output_processor),
    136       stream(s), data_callback(cb), user_ptr(ptr)
    137 {
    138   if (input_processor && output_processor) {
    139     fill_internal = &cubeb_resampler_speex::fill_internal_duplex;
    140   } else if (input_processor) {
    141     fill_internal = &cubeb_resampler_speex::fill_internal_input;
    142   } else if (output_processor) {
    143     fill_internal = &cubeb_resampler_speex::fill_internal_output;
    144   }
    145 }
    146 
    147 template <typename T, typename InputProcessor, typename OutputProcessor>
    148 cubeb_resampler_speex<T, InputProcessor,
    149                       OutputProcessor>::~cubeb_resampler_speex()
    150 {
    151 }
    152 
    153 template <typename T, typename InputProcessor, typename OutputProcessor>
    154 long
    155 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill(
    156     void * input_buffer, long * input_frames_count, void * output_buffer,
    157     long output_frames_needed)
    158 {
    159   /* Input and output buffers, typed */
    160   T * in_buffer = reinterpret_cast<T *>(input_buffer);
    161   T * out_buffer = reinterpret_cast<T *>(output_buffer);
    162   return (this->*fill_internal)(in_buffer, input_frames_count, out_buffer,
    163                                 output_frames_needed);
    164 }
    165 
    166 template <typename T, typename InputProcessor, typename OutputProcessor>
    167 long
    168 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill_internal_output(
    169     T * input_buffer, long * input_frames_count, T * output_buffer,
    170     long output_frames_needed)
    171 {
    172   assert(!input_buffer && (!input_frames_count || *input_frames_count == 0) &&
    173          output_buffer && output_frames_needed);
    174 
    175   if (!draining) {
    176     long got = 0;
    177     T * out_unprocessed = nullptr;
    178     long output_frames_before_processing = 0;
    179 
    180     /* fill directly the input buffer of the output processor to save a copy */
    181     output_frames_before_processing =
    182         output_processor->input_needed_for_output(output_frames_needed);
    183 
    184     out_unprocessed =
    185         output_processor->input_buffer(output_frames_before_processing);
    186 
    187     got = data_callback(stream, user_ptr, nullptr, out_unprocessed,
    188                         output_frames_before_processing);
    189 
    190     if (got < output_frames_before_processing) {
    191       draining = true;
    192 
    193       if (got < 0) {
    194         return got;
    195       }
    196     }
    197 
    198     output_processor->written(got);
    199   }
    200 
    201   /* Process the output. If not enough frames have been returned from the
    202    * callback, drain the processors. */
    203   return output_processor->output(output_buffer, output_frames_needed);
    204 }
    205 
    206 template <typename T, typename InputProcessor, typename OutputProcessor>
    207 long
    208 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill_internal_input(
    209     T * input_buffer, long * input_frames_count, T * output_buffer,
    210     long /*output_frames_needed*/)
    211 {
    212   assert(input_buffer && input_frames_count && *input_frames_count &&
    213          !output_buffer);
    214 
    215   /* The input data, after eventual resampling. This is passed to the callback.
    216    */
    217   T * resampled_input = nullptr;
    218   uint32_t resampled_frame_count =
    219       input_processor->output_for_input(*input_frames_count);
    220 
    221   /* process the input, and present exactly `output_frames_needed` in the
    222    * callback. */
    223   input_processor->input(input_buffer, *input_frames_count);
    224 
    225   /* resampled_frame_count == 0 happens if the resampler
    226    * doesn't have enough input frames buffered to produce 1 resampled frame. */
    227   if (resampled_frame_count == 0) {
    228     return *input_frames_count;
    229   }
    230 
    231   size_t frames_resampled = 0;
    232   resampled_input =
    233       input_processor->output(resampled_frame_count, &frames_resampled);
    234   *input_frames_count = frames_resampled;
    235 
    236   long got = data_callback(stream, user_ptr, resampled_input, nullptr,
    237                            resampled_frame_count);
    238 
    239   /* Return the number of initial input frames or part of it.
    240    * Since output_frames_needed == 0 in input scenario, the only
    241    * available number outside resampler is the initial number of frames. */
    242   return (*input_frames_count) * (got / resampled_frame_count);
    243 }
    244 
    245 template <typename T, typename InputProcessor, typename OutputProcessor>
    246 long
    247 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill_internal_duplex(
    248     T * in_buffer, long * input_frames_count, T * out_buffer,
    249     long output_frames_needed)
    250 {
    251   if (draining) {
    252     // discard input and drain any signal remaining in the resampler.
    253     return output_processor->output(out_buffer, output_frames_needed);
    254   }
    255 
    256   /* The input data, after eventual resampling. This is passed to the callback.
    257    */
    258   T * resampled_input = nullptr;
    259   /* The output buffer passed down in the callback, that might be resampled. */
    260   T * out_unprocessed = nullptr;
    261   long output_frames_before_processing = 0;
    262   /* The number of frames returned from the callback. */
    263   long got = 0;
    264 
    265   /* We need to determine how much frames to present to the consumer.
    266    * - If we have a two way stream, but we're only resampling input, we resample
    267    * the input to the number of output frames.
    268    * - If we have a two way stream, but we're only resampling the output, we
    269    * resize the input buffer of the output resampler to the number of input
    270    * frames, and we resample it afterwards.
    271    * - If we resample both ways, we resample the input to the number of frames
    272    * we would need to pass down to the consumer (before resampling the output),
    273    * get the output data, and resample it to the number of frames needed by the
    274    * caller. */
    275 
    276   output_frames_before_processing =
    277       output_processor->input_needed_for_output(output_frames_needed);
    278   /* fill directly the input buffer of the output processor to save a copy */
    279   out_unprocessed =
    280       output_processor->input_buffer(output_frames_before_processing);
    281 
    282   if (in_buffer) {
    283     /* process the input, and present exactly `output_frames_needed` in the
    284      * callback. */
    285     input_processor->input(in_buffer, *input_frames_count);
    286 
    287     size_t frames_resampled = 0;
    288     resampled_input = input_processor->output(output_frames_before_processing,
    289                                               &frames_resampled);
    290     *input_frames_count = frames_resampled;
    291   } else {
    292     resampled_input = nullptr;
    293   }
    294 
    295   got = data_callback(stream, user_ptr, resampled_input, out_unprocessed,
    296                       output_frames_before_processing);
    297 
    298   if (got < output_frames_before_processing) {
    299     draining = true;
    300 
    301     if (got < 0) {
    302       return got;
    303     }
    304   }
    305 
    306   output_processor->written(got);
    307 
    308   input_processor->drop_audio_if_needed();
    309 
    310   /* Process the output. If not enough frames have been returned from the
    311    * callback, drain the processors. */
    312   got = output_processor->output(out_buffer, output_frames_needed);
    313 
    314   output_processor->drop_audio_if_needed();
    315 
    316   return got;
    317 }
    318 
    319 /* Resampler C API */
    320 
    321 cubeb_resampler *
    322 cubeb_resampler_create(cubeb_stream * stream,
    323                        cubeb_stream_params * input_params,
    324                        cubeb_stream_params * output_params,
    325                        unsigned int target_rate, cubeb_data_callback callback,
    326                        void * user_ptr, cubeb_resampler_quality quality,
    327                        cubeb_resampler_reclock reclock)
    328 {
    329   cubeb_sample_format format;
    330 
    331   assert(input_params || output_params);
    332 
    333   if (input_params) {
    334     format = input_params->format;
    335   } else {
    336     format = output_params->format;
    337   }
    338 
    339   switch (format) {
    340   case CUBEB_SAMPLE_S16NE:
    341     return cubeb_resampler_create_internal<short>(
    342         stream, input_params, output_params, target_rate, callback, user_ptr,
    343         quality, reclock);
    344   case CUBEB_SAMPLE_FLOAT32NE:
    345     return cubeb_resampler_create_internal<float>(
    346         stream, input_params, output_params, target_rate, callback, user_ptr,
    347         quality, reclock);
    348   default:
    349     assert(false);
    350     return nullptr;
    351   }
    352 }
    353 
    354 long
    355 cubeb_resampler_fill(cubeb_resampler * resampler, void * input_buffer,
    356                      long * input_frames_count, void * output_buffer,
    357                      long output_frames_needed)
    358 {
    359   return resampler->fill(input_buffer, input_frames_count, output_buffer,
    360                          output_frames_needed);
    361 }
    362 
    363 void
    364 cubeb_resampler_destroy(cubeb_resampler * resampler)
    365 {
    366   delete resampler;
    367 }
    368 
    369 long
    370 cubeb_resampler_latency(cubeb_resampler * resampler)
    371 {
    372   return resampler->latency();
    373 }