git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / audio / resampler / audio_resampler.c
1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (audio_resampler.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <string.h>
24
25 #include <string/stdstring.h>
26 #include <features/features_cpu.h>
27 #include <file/config_file_userdata.h>
28
29 #include <audio/audio_resampler.h>
30
31 static void resampler_null_process(void *a, struct resampler_data *b) { }
32 static void resampler_null_free(void *a) { }
33 static void *resampler_null_init(const struct resampler_config *a, double b,
34       enum resampler_quality c, resampler_simd_mask_t d) { return (void*)0; }
35
36 retro_resampler_t null_resampler = {
37    resampler_null_init,
38    resampler_null_process,
39    resampler_null_free,
40    RESAMPLER_API_VERSION,
41    "null",
42    "null"
43 };
44
45 static const retro_resampler_t *resampler_drivers[] = {
46    &sinc_resampler,
47 #ifdef HAVE_CC_RESAMPLER
48    &CC_resampler,
49 #endif
50 #ifdef HAVE_NEAREST_RESAMPLER
51    &nearest_resampler,
52 #endif
53    &null_resampler,
54    NULL,
55 };
56
57 static const struct resampler_config resampler_config = {
58    config_userdata_get_float,
59    config_userdata_get_int,
60    config_userdata_get_float_array,
61    config_userdata_get_int_array,
62    config_userdata_get_string,
63    config_userdata_free,
64 };
65
66 /**
67  * find_resampler_driver_index:
68  * @ident                      : Identifier of resampler driver to find.
69  *
70  * Finds resampler driver index by @ident name.
71  *
72  * Returns: resampler driver index if resampler driver was found, otherwise
73  * -1.
74  **/
75 static int find_resampler_driver_index(const char *ident)
76 {
77    unsigned i;
78
79    for (i = 0; resampler_drivers[i]; i++)
80       if (string_is_equal_noncase(ident, resampler_drivers[i]->ident))
81          return i;
82    return -1;
83 }
84
85 /**
86  * find_resampler_driver:
87  * @ident                      : Identifier of resampler driver to find.
88  *
89  * Finds resampler by @ident name.
90  *
91  * Returns: resampler driver if resampler driver was found, otherwise
92  * NULL.
93  **/
94 static const retro_resampler_t *find_resampler_driver(const char *ident)
95 {
96    int i = find_resampler_driver_index(ident);
97
98    if (i >= 0)
99       return resampler_drivers[i];
100
101    return resampler_drivers[0];
102 }
103
104 /**
105  * resampler_append_plugs:
106  * @re                         : Resampler handle
107  * @backend                    : Resampler backend that is about to be set.
108  * @bw_ratio                   : Bandwidth ratio.
109  *
110  * Initializes resampler driver based on queried CPU features.
111  *
112  * Returns: true (1) if successfully initialized, otherwise false (0).
113  **/
114 static bool resampler_append_plugs(void **re,
115       const retro_resampler_t **backend,
116       enum resampler_quality quality,
117       double bw_ratio)
118 {
119    resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();
120
121    if (*backend)
122       *re = (*backend)->init(&resampler_config, bw_ratio, quality, mask);
123
124    if (!*re)
125       return false;
126    return true;
127 }
128
129
130 /**
131  * audio_resampler_driver_find_handle:
132  * @idx                : index of driver to get handle to.
133  *
134  * Returns: handle to audio resampler driver at index. Can be NULL
135  * if nothing found.
136  **/
137 const void *audio_resampler_driver_find_handle(int idx)
138 {
139    const void *drv = resampler_drivers[idx];
140    if (!drv)
141       return NULL;
142    return drv;
143 }
144
145 /**
146  * audio_resampler_driver_find_ident:
147  * @idx                : index of driver to get handle to.
148  *
149  * Returns: Human-readable identifier of audio resampler driver at index.
150  * Can be NULL if nothing found.
151  **/
152 const char *audio_resampler_driver_find_ident(int idx)
153 {
154    const retro_resampler_t *drv = resampler_drivers[idx];
155    if (!drv)
156       return NULL;
157    return drv->ident;
158 }
159
160 /**
161  * retro_resampler_realloc:
162  * @re                         : Resampler handle
163  * @backend                    : Resampler backend that is about to be set.
164  * @ident                      : Identifier name for resampler we want.
165  * @bw_ratio                   : Bandwidth ratio.
166  *
167  * Reallocates resampler. Will free previous handle before
168  * allocating a new one. If ident is NULL, first resampler will be used.
169  *
170  * Returns: true (1) if successful, otherwise false (0).
171  **/
172 bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
173       const char *ident, enum resampler_quality quality, double bw_ratio)
174 {
175    if (*re && *backend)
176       (*backend)->free(*re);
177
178    *re      = NULL;
179    *backend = find_resampler_driver(ident);
180
181    if (!resampler_append_plugs(re, backend, quality, bw_ratio))
182    {
183       if (!*re)
184          *backend = NULL;
185       return false;
186    }
187
188    return true;
189 }