core/audio.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. | ||
| 2 | // http://avisynth.nl | ||
| 3 | |||
| 4 | // This program is free software; you can redistribute it and/or modify | ||
| 5 | // it under the terms of the GNU General Public License as published by | ||
| 6 | // the Free Software Foundation; either version 2 of the License, or | ||
| 7 | // (at your option) any later version. | ||
| 8 | // | ||
| 9 | // This program is distributed in the hope that it will be useful, | ||
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | // GNU General Public License for more details. | ||
| 13 | // | ||
| 14 | // You should have received a copy of the GNU General Public License | ||
| 15 | // along with this program; if not, write to the Free Software | ||
| 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit | ||
| 17 | // http://www.gnu.org/copyleft/gpl.html . | ||
| 18 | // | ||
| 19 | // Linking Avisynth statically or dynamically with other modules is making a | ||
| 20 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU | ||
| 21 | // General Public License cover the whole combination. | ||
| 22 | // | ||
| 23 | // As a special exception, the copyright holders of Avisynth give you | ||
| 24 | // permission to link Avisynth with independent modules that communicate with | ||
| 25 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license | ||
| 26 | // terms of these independent modules, and to copy and distribute the | ||
| 27 | // resulting combined work under terms of your choice, provided that | ||
| 28 | // every copy of the combined work is accompanied by a complete copy of | ||
| 29 | // the source code of Avisynth (the version of Avisynth used to produce the | ||
| 30 | // combined work), being distributed under the terms of the GNU General | ||
| 31 | // Public License plus this exception. An independent module is a module | ||
| 32 | // which is not derived from or based on Avisynth, such as 3rd-party filters, | ||
| 33 | // import and export plugins, or graphical user interfaces. | ||
| 34 | |||
| 35 | #include <avisynth.h> | ||
| 36 | |||
| 37 | #ifdef AVS_WINDOWS | ||
| 38 | #include <avs/win.h> | ||
| 39 | #else | ||
| 40 | #include <avs/posix.h> | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #include <avs/minmax.h> | ||
| 44 | #include "internal.h" | ||
| 45 | |||
| 46 | #include "audio.h" | ||
| 47 | #include "../convert/convert_audio.h" | ||
| 48 | #include <cstdio> | ||
| 49 | #include <cstdlib> | ||
| 50 | #include <new> | ||
| 51 | #include <algorithm> | ||
| 52 | |||
| 53 | #define BIGBUFFSIZE (2048*1024) // Use a 2Mb buffer for EnsureVBRMP3Sync seeking & Normalize scanning | ||
| 54 | |||
| 55 | #ifndef INT16_MAX | ||
| 56 | #define INT16_MAX 32767 | ||
| 57 | #endif | ||
| 58 | #ifndef INT16_MIN | ||
| 59 | #define INT16_MIN (-32768) | ||
| 60 | #endif | ||
| 61 | #ifndef INT32_MAX | ||
| 62 | #define INT32_MAX 2147483647 | ||
| 63 | #endif | ||
| 64 | #ifndef INT32_MIN | ||
| 65 | #define INT32_MIN (-2147483647 - 1) | ||
| 66 | #endif | ||
| 67 | #ifndef INT64_MAX | ||
| 68 | #define INT64_MAX 9223372036854775807LL | ||
| 69 | #endif | ||
| 70 | #ifndef INT64_MIN | ||
| 71 | #define INT64_MIN (-9223372036854775807LL - 1) | ||
| 72 | #endif | ||
| 73 | |||
| 74 | 13 | static int64_t signed_saturated_add64(int64_t x, int64_t y) { | |
| 75 | // determine the lower or upper bound of the result | ||
| 76 |
2/2✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 4 taken 7 times.
|
13 | int64_t ret = (x < 0) ? INT64_MIN : INT64_MAX; |
| 77 | // this is always well defined: | ||
| 78 | // if x < 0 this adds a positive value to INT64_MIN | ||
| 79 | // if x > 0 this subtracts a positive value from INT64_MAX | ||
| 80 | 13 | int64_t comp = ret - x; | |
| 81 | // the condition is equivalent to this longer one. | ||
| 82 | #ifdef MSVC_PURE | ||
| 83 | // Due to a compiler bug (bad code gen) in VS2022 MSVC 17.12.3 and before, | ||
| 84 | // the short version of the condition cannot be used safely. | ||
| 85 | // Issue is reported: https://developercommunity.visualstudio.com/t/Bad-code-gen-with-inlined-functions-with/10813706 | ||
| 86 | // Workaround is presented here, until the fix. | ||
| 87 | // They seem to have it fixed in 17.13.1. Anyway, we keep this code path separated. | ||
| 88 | if ((x < 0 && y > comp) || (x >= 0 && y <= comp)) | ||
| 89 | #else | ||
| 90 |
1/2✓ Branch 5 → 6 taken 13 times.
✗ Branch 5 → 7 not taken.
|
13 | if ((x < 0) == (y > comp)) // short, quicker one |
| 91 | #endif | ||
| 92 | 13 | ret = x + y; | |
| 93 | 13 | return ret; | |
| 94 | } | ||
| 95 | |||
| 96 | // ----------- Channels | ||
| 97 | // ffmpeg extras are not handled, only the first 18 bits | ||
| 98 | // which is defined in WAVEFORMATEXTENSIBLE and Avisynth.h AvsChannelMask | ||
| 99 | |||
| 100 | struct channel_name_t { | ||
| 101 | const char* name; | ||
| 102 | const char* description; | ||
| 103 | }; | ||
| 104 | |||
| 105 | static const struct channel_name_t channel_names[] = { | ||
| 106 | { "FL", "front left" }, | ||
| 107 | { "FR", "front right" }, | ||
| 108 | { "FC", "front center" }, | ||
| 109 | { "LFE", "low frequency" }, | ||
| 110 | { "BL", "back left" }, | ||
| 111 | { "BR", "back right" }, | ||
| 112 | { "FLC", "front left-of-center" }, | ||
| 113 | { "FRC", "front right-of-center" }, | ||
| 114 | { "BC", "back center" }, | ||
| 115 | { "SL", "side left" }, | ||
| 116 | { "SR", "side right" }, | ||
| 117 | { "TC", "top center" }, | ||
| 118 | { "TFL", "top front left" }, | ||
| 119 | { "TFC", "top front center" }, | ||
| 120 | { "TFR", "top front right" }, | ||
| 121 | { "TBL", "top back left" }, | ||
| 122 | { "TBC", "top back center" }, | ||
| 123 | { "TBR", "top back right" } | ||
| 124 | }; | ||
| 125 | |||
| 126 | constexpr auto channel_names_size = sizeof(channel_names) / sizeof(channel_name_t); | ||
| 127 | |||
| 128 | struct channel_layout_name { | ||
| 129 | const char* name; | ||
| 130 | ChannelLayoutDescriptor_t layout; | ||
| 131 | }; | ||
| 132 | |||
| 133 | static const struct channel_layout_name channel_layout_map[] = { | ||
| 134 | { "mono", AVS_CHANNEL_LAYOUT_MASK_MONO }, | ||
| 135 | { "stereo", AVS_CHANNEL_LAYOUT_MASK_STEREO }, | ||
| 136 | { "2.1", AVS_CHANNEL_LAYOUT_MASK_2POINT1 }, | ||
| 137 | { "3.0", AVS_CHANNEL_LAYOUT_MASK_SURROUND }, | ||
| 138 | { "3.0(back)", AVS_CHANNEL_LAYOUT_MASK_2_1 }, | ||
| 139 | { "4.0", AVS_CHANNEL_LAYOUT_MASK_4POINT0 }, | ||
| 140 | { "quad", AVS_CHANNEL_LAYOUT_MASK_QUAD }, | ||
| 141 | { "quad(side)", AVS_CHANNEL_LAYOUT_MASK_2_2 }, | ||
| 142 | { "3.1", AVS_CHANNEL_LAYOUT_MASK_3POINT1 }, | ||
| 143 | { "5.0", AVS_CHANNEL_LAYOUT_MASK_5POINT0_BACK }, | ||
| 144 | { "5.0(side)", AVS_CHANNEL_LAYOUT_MASK_5POINT0 }, | ||
| 145 | { "4.1", AVS_CHANNEL_LAYOUT_MASK_4POINT1 }, | ||
| 146 | { "5.1", AVS_CHANNEL_LAYOUT_MASK_5POINT1_BACK }, | ||
| 147 | { "5.1(side)", AVS_CHANNEL_LAYOUT_MASK_5POINT1 }, | ||
| 148 | { "6.0", AVS_CHANNEL_LAYOUT_MASK_6POINT0 }, | ||
| 149 | { "6.0(front)", AVS_CHANNEL_LAYOUT_MASK_6POINT0_FRONT }, | ||
| 150 | { "hexagonal", AVS_CHANNEL_LAYOUT_MASK_HEXAGONAL }, | ||
| 151 | { "6.1", AVS_CHANNEL_LAYOUT_MASK_6POINT1 }, | ||
| 152 | { "6.1(back)", AVS_CHANNEL_LAYOUT_MASK_6POINT1_BACK }, | ||
| 153 | { "6.1(front)", AVS_CHANNEL_LAYOUT_MASK_6POINT1_FRONT }, | ||
| 154 | { "7.0", AVS_CHANNEL_LAYOUT_MASK_7POINT0 }, | ||
| 155 | { "7.0(front)", AVS_CHANNEL_LAYOUT_MASK_7POINT0_FRONT }, | ||
| 156 | { "7.1", AVS_CHANNEL_LAYOUT_MASK_7POINT1 }, | ||
| 157 | { "7.1(wide)", AVS_CHANNEL_LAYOUT_MASK_7POINT1_WIDE_BACK }, | ||
| 158 | { "7.1(wide-side)", AVS_CHANNEL_LAYOUT_MASK_7POINT1_WIDE }, | ||
| 159 | { "7.1(top)", AVS_CHANNEL_LAYOUT_MASK_7POINT1_TOP_BACK }, | ||
| 160 | { "octagonal", AVS_CHANNEL_LAYOUT_MASK_OCTAGONAL }, | ||
| 161 | { "cube", AVS_CHANNEL_LAYOUT_MASK_CUBE }, | ||
| 162 | //{ "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL } | ||
| 163 | //{ "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, }, | ||
| 164 | //{ "22.2", AV_CHANNEL_LAYOUT_22POINT2, }, | ||
| 165 | }; | ||
| 166 | |||
| 167 | constexpr auto channel_layout_map_size = sizeof(channel_layout_map) / sizeof(channel_layout_name); | ||
| 168 | |||
| 169 | 2 | static unsigned int av_get_default_channel_layout(int nb_channels) { | |
| 170 |
1/2✓ Branch 6 → 3 taken 4 times.
✗ Branch 6 → 7 not taken.
|
4 | for (int i = 0; i < channel_layout_map_size; i++) |
| 171 |
2/2✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 2 times.
|
4 | if (nb_channels == channel_layout_map[i].layout.nb_channels) |
| 172 | 2 | return channel_layout_map[i].layout.mask; | |
| 173 | ✗ | return 0; | |
| 174 | } | ||
| 175 | |||
| 176 | // similar to old ffmpeg method | ||
| 177 | ✗ | static unsigned int get_channel_layout_single(const char* name, size_t name_len) | |
| 178 | { | ||
| 179 | // combined layout name | ||
| 180 | ✗ | for (int i = 0; i < channel_layout_map_size; i++) { | |
| 181 | ✗ | if (strlen(channel_layout_map[i].name) == name_len && | |
| 182 | ✗ | !memcmp(channel_layout_map[i].name, name, name_len)) | |
| 183 | ✗ | return channel_layout_map[i].layout.mask; | |
| 184 | } | ||
| 185 | // individual channel name | ||
| 186 | ✗ | for (int i = 0; i < channel_names_size; i++) | |
| 187 | ✗ | if (channel_names[i].name && | |
| 188 | ✗ | strlen(channel_names[i].name) == name_len && | |
| 189 | ✗ | !memcmp(channel_names[i].name, name, name_len)) | |
| 190 | ✗ | return (unsigned int)1 << i; | |
| 191 | |||
| 192 | //get default by number of channels, syntax: number ending with 'c' | ||
| 193 | char* end; | ||
| 194 | ✗ | errno = 0; | |
| 195 | ✗ | long i = std::strtol(name, &end, 10); | |
| 196 | |||
| 197 | ✗ | if (!errno && (end + 1 - name == name_len && *end == 'c')) | |
| 198 | ✗ | return av_get_default_channel_layout(i); | |
| 199 | |||
| 200 | // return the directly given mask | ||
| 201 | ✗ | errno = 0; | |
| 202 | ✗ | long long layout = std::strtoll(name, &end, 0); | |
| 203 | ✗ | if (!errno && end - name == name_len) { | |
| 204 | ✗ | if (layout > std::numeric_limits<unsigned int>::max()) | |
| 205 | ✗ | return 0; | |
| 206 | ✗ | return (unsigned int)std::max(layout, 0LL); | |
| 207 | } | ||
| 208 | ✗ | return 0; | |
| 209 | } | ||
| 210 | |||
| 211 | // returns layout mask from the layout name or channel name | ||
| 212 | // or from their combinations | ||
| 213 | ✗ | unsigned int av_get_channel_layout(const char* name) | |
| 214 | { | ||
| 215 | const char* n, * e; | ||
| 216 | ✗ | const char* name_end = name + strlen(name); | |
| 217 | ✗ | unsigned int layout = 0, layout_single; | |
| 218 | |||
| 219 | ✗ | if(!_stricmp(name, "speaker_all")) | |
| 220 | ✗ | return AvsChannelMask::MASK_SPEAKER_ALL; | |
| 221 | |||
| 222 | ✗ | for (n = name; n < name_end; n = e + 1) { | |
| 223 | ✗ | for (e = n; e < name_end && *e != '+' && *e != '|'; e++); | |
| 224 | ✗ | layout_single = get_channel_layout_single(n, e - n); | |
| 225 | ✗ | if (!layout_single) | |
| 226 | ✗ | return 0; | |
| 227 | ✗ | layout |= layout_single; | |
| 228 | } | ||
| 229 | ✗ | return layout; | |
| 230 | } | ||
| 231 | |||
| 232 | 2 | unsigned int GetDefaultChannelLayout(int nChannels) { | |
| 233 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
|
2 | if (nChannels < 1 || nChannels > 8) |
| 234 | ✗ | return 0; | |
| 235 | 2 | return av_get_default_channel_layout(nChannels); | |
| 236 | |||
| 237 | /* old one: | ||
| 238 | // Called from VfW export as well | ||
| 239 | // 3.7.3 changes some defaults to match ffmpeg | ||
| 240 | // 3 channels: Surround to 2.1 | ||
| 241 | // 4 channels: Quad to 4.0 | ||
| 242 | // 6 channels: 6.1(back) to 6.1 | ||
| 243 | const int SpeakerMasks[9] = | ||
| 244 | { 0, | ||
| 245 | // chnls name layout ffmpeg | ||
| 246 | 0x00004, // 1 mono -- -- FC AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) | ||
| 247 | 0x00003, // 2 stereo FL FR AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) | ||
| 248 | 0x0000B, // 3 2.1 FL FR LFE AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) | ||
| 249 | // 0x00007, // 3 3.0 FL FR FC AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) | ||
| 250 | 0x00107, // 4 4.0 FL FR FC -- -- -- -- -- BC AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) | ||
| 251 | // 0x00033, // 4 quad FL FR -- -- BL BR AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) | ||
| 252 | 0x00037, // 5 5.0 FL FR FC -- BL BR AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) | ||
| 253 | 0x0003F, // 6 5.1 FL FR FC LFE BL BR AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) | ||
| 254 | 0x0070F, // 7 6.1 FL FR FC LFE -- -- -- -- BC SL SR AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) | ||
| 255 | // 0x0013F, // 7 6.1(back) FL FR FC LFE BL BR -- -- BC AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) | ||
| 256 | 0x0063F, // 8 7.1 FL FR FC LFE BL BR -- -- -- SL SR AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) | ||
| 257 | }; | ||
| 258 | return SpeakerMasks[nChannels]; | ||
| 259 | */ | ||
| 260 | } | ||
| 261 | |||
| 262 | // popcount | ||
| 263 | ✗ | static int channelcount_from_mask(unsigned int mask) | |
| 264 | { | ||
| 265 | unsigned long long y; | ||
| 266 | ✗ | y = mask * 0x0002000400080010ULL; | |
| 267 | ✗ | y = y & 0x1111111111111111ULL; | |
| 268 | ✗ | y = y * 0x1111111111111111ULL; | |
| 269 | ✗ | y = y >> 60; | |
| 270 | ✗ | return (int)y; | |
| 271 | } | ||
| 272 | |||
| 273 | // gets the 'idx'th bit=1 from layout_mask and returns its bit index | ||
| 274 | // or -1 if not found | ||
| 275 | // index can be used to channel_names | ||
| 276 | ✗ | enum AVSChannel av_channel_layout_channel_from_index(const unsigned int channel_layout_mask, | |
| 277 | unsigned int idx) | ||
| 278 | { | ||
| 279 | ✗ | const int nb_channels = channelcount_from_mask(channel_layout_mask); | |
| 280 | ✗ | if ((int)idx >= nb_channels) | |
| 281 | ✗ | return AVSChannel::AVS_CHAN_IDX_NONE; | |
| 282 | |||
| 283 | ✗ | for (int i = 0; i < 32; i++) { // unsigned int 32 bits | |
| 284 | ✗ | if ((1ULL << i) & channel_layout_mask && !idx--) | |
| 285 | ✗ | return (enum AVSChannel)i; | |
| 286 | } | ||
| 287 | |||
| 288 | ✗ | return AVSChannel::AVS_CHAN_IDX_NONE; | |
| 289 | } | ||
| 290 | |||
| 291 | ✗ | std::string channel_layout_to_str(const unsigned int channel_layout_mask) | |
| 292 | { | ||
| 293 | // special | ||
| 294 | ✗ | if (channel_layout_mask == AvsChannelMask::MASK_SPEAKER_ALL) | |
| 295 | ✗ | return "speaker_all"; | |
| 296 | |||
| 297 | // find direct match | ||
| 298 | ✗ | for (int i = 0; i < channel_layout_map_size; i++) { | |
| 299 | ✗ | if (channel_layout_mask == channel_layout_map[i].layout.mask) { | |
| 300 | ✗ | return channel_layout_map[i].name; | |
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | // return channel combo: | ||
| 305 | // e.g. "2 channels (FC+LFE)" | ||
| 306 | |||
| 307 | ✗ | const int nb_channels = channelcount_from_mask(channel_layout_mask); | |
| 308 | |||
| 309 | ✗ | std::string bp; | |
| 310 | |||
| 311 | ✗ | if (nb_channels) | |
| 312 | ✗ | bp = std::to_string(nb_channels) + " channels ("; | |
| 313 | ✗ | for (int i = 0; i < nb_channels; i++) { | |
| 314 | ✗ | enum AVSChannel ch = av_channel_layout_channel_from_index(channel_layout_mask, i); | |
| 315 | |||
| 316 | ✗ | if (i) | |
| 317 | ✗ | bp += "+"; | |
| 318 | |||
| 319 | ✗ | if (ch == AVSChannel::AVS_CHAN_IDX_NONE) | |
| 320 | ✗ | bp += "NONE"; | |
| 321 | ✗ | else if ((unsigned int)ch < channel_names_size) | |
| 322 | ✗ | bp += channel_names[(unsigned int)ch].name; | |
| 323 | } | ||
| 324 | ✗ | if (nb_channels) { | |
| 325 | ✗ | bp += ")"; | |
| 326 | ✗ | return bp; | |
| 327 | } | ||
| 328 | ✗ | bp = "(Error. Mask=" + std::to_string(channel_layout_mask) + ")"; | |
| 329 | ✗ | return bp; | |
| 330 | ✗ | } | |
| 331 | |||
| 332 | /******************************************************************** | ||
| 333 | ***** Declare index of new filters for Avisynth's filter engine ***** | ||
| 334 | ********************************************************************/ | ||
| 335 | |||
| 336 | extern const AVSFunction Audio_filters[] = { | ||
| 337 | { "DelayAudio", BUILTIN_FUNC_PREFIX, "cf", DelayAudio::Create }, | ||
| 338 | { "AmplifydB", BUILTIN_FUNC_PREFIX, "cf+", Amplify::Create_dB }, | ||
| 339 | { "Amplify", BUILTIN_FUNC_PREFIX, "cf+", Amplify::Create }, | ||
| 340 | { "AssumeSampleRate", BUILTIN_FUNC_PREFIX, "ci", AssumeRate::Create }, | ||
| 341 | { "Normalize", BUILTIN_FUNC_PREFIX, "c[volume]f[show]b", Normalize::Create }, | ||
| 342 | { "MixAudio", BUILTIN_FUNC_PREFIX, "cc[clip1_factor]f[clip2_factor]f", MixAudio::Create }, | ||
| 343 | { "ResampleAudio", BUILTIN_FUNC_PREFIX, "ci[]i", ResampleAudio::Create }, | ||
| 344 | { "ConvertToMono", BUILTIN_FUNC_PREFIX, "c", ConvertToMono::Create }, | ||
| 345 | { "EnsureVBRMP3Sync", BUILTIN_FUNC_PREFIX, "c", EnsureVBRMP3Sync::Create }, | ||
| 346 | { "MergeChannels", BUILTIN_FUNC_PREFIX, "c+", MergeChannels::Create }, | ||
| 347 | { "MonoToStereo", BUILTIN_FUNC_PREFIX, "cc", MergeChannels::Create }, | ||
| 348 | { "GetLeftChannel", BUILTIN_FUNC_PREFIX, "c", GetChannel::Create_left }, | ||
| 349 | { "GetRightChannel", BUILTIN_FUNC_PREFIX, "c", GetChannel::Create_right }, | ||
| 350 | { "GetChannel", BUILTIN_FUNC_PREFIX, "ci+", GetChannel::Create_n }, | ||
| 351 | { "GetChannels", BUILTIN_FUNC_PREFIX, "ci+", GetChannel::Create_n }, // Alias to ease use! | ||
| 352 | { "KillVideo", BUILTIN_FUNC_PREFIX, "c", KillVideo::Create }, | ||
| 353 | { "KillAudio", BUILTIN_FUNC_PREFIX, "c", KillAudio::Create }, | ||
| 354 | { "ConvertAudioTo16bit", BUILTIN_FUNC_PREFIX, "c", ConvertAudio::Create_16bit }, // in convertaudio.cpp | ||
| 355 | { "ConvertAudioTo8bit", BUILTIN_FUNC_PREFIX, "c", ConvertAudio::Create_8bit }, | ||
| 356 | { "ConvertAudioTo24bit", BUILTIN_FUNC_PREFIX, "c", ConvertAudio::Create_24bit }, | ||
| 357 | { "ConvertAudioTo32bit", BUILTIN_FUNC_PREFIX, "c", ConvertAudio::Create_32bit }, | ||
| 358 | { "ConvertAudioToFloat", BUILTIN_FUNC_PREFIX, "c", ConvertAudio::Create_float }, | ||
| 359 | { "ConvertAudio", BUILTIN_FUNC_PREFIX, "cii", ConvertAudio::Create_Any }, // For plugins to Invoke() | ||
| 360 | { "SetChannelMask", BUILTIN_FUNC_PREFIX, "cbi", SetChannelMask::Create }, | ||
| 361 | { "SetChannelMask", BUILTIN_FUNC_PREFIX, "cs", SetChannelMask::Create }, | ||
| 362 | { 0 } | ||
| 363 | }; | ||
| 364 | |||
| 365 | // Note - floats should not be clipped - they will be clipped, when they are converted back to ints. | ||
| 366 | // Vdub can handle 8/16 bit, and reads 32bit, but cannot play/convert it. Floats doesn't make sense | ||
| 367 | // in AVI. So for now convert back to 16 bit always. | ||
| 368 | |||
| 369 | // Always! FIXME: Most int64's are often cropped to ints - count is ok to be int, but not start | ||
| 370 | |||
| 371 | // For plugins to env->Invoke() | ||
| 372 | |||
| 373 | ✗ | AVSValue __cdecl ConvertAudio::Create_Any(AVSValue args, void*, IScriptEnvironment*) { | |
| 374 | ✗ | return Create(args[0].AsClip(), args[1].AsInt(), args[2].AsInt()); | |
| 375 | } | ||
| 376 | |||
| 377 | // For explicit conversions | ||
| 378 | |||
| 379 | ✗ | AVSValue __cdecl ConvertAudio::Create_16bit(AVSValue args, void*, IScriptEnvironment*) { | |
| 380 | ✗ | return Create(args[0].AsClip(), SAMPLE_INT16, SAMPLE_INT16); | |
| 381 | } | ||
| 382 | |||
| 383 | ✗ | AVSValue __cdecl ConvertAudio::Create_8bit(AVSValue args, void*, IScriptEnvironment*) { | |
| 384 | ✗ | return Create(args[0].AsClip(), SAMPLE_INT8, SAMPLE_INT8); | |
| 385 | } | ||
| 386 | |||
| 387 | |||
| 388 | ✗ | AVSValue __cdecl ConvertAudio::Create_32bit(AVSValue args, void*, IScriptEnvironment*) { | |
| 389 | ✗ | return Create(args[0].AsClip(), SAMPLE_INT32, SAMPLE_INT32); | |
| 390 | } | ||
| 391 | |||
| 392 | ✗ | AVSValue __cdecl ConvertAudio::Create_float(AVSValue args, void*, IScriptEnvironment*) { | |
| 393 | ✗ | return Create(args[0].AsClip(), SAMPLE_FLOAT, SAMPLE_FLOAT); | |
| 394 | } | ||
| 395 | |||
| 396 | ✗ | AVSValue __cdecl ConvertAudio::Create_24bit(AVSValue args, void*, IScriptEnvironment*) { | |
| 397 | ✗ | return Create(args[0].AsClip(), SAMPLE_INT24, SAMPLE_INT24); | |
| 398 | } | ||
| 399 | |||
| 400 | |||
| 401 | #if defined(X86_32) && defined(MSVC) && !defined(__clang__) | ||
| 402 | void FilterUD_mmx(short *Xp, unsigned Ph, int _inc, int _dhb, short *p_Imp, unsigned End); | ||
| 403 | #endif | ||
| 404 | |||
| 405 | |||
| 406 | /************************************* | ||
| 407 | ******* Assume SampleRate ******** | ||
| 408 | *************************************/ | ||
| 409 | |||
| 410 | 1 | AssumeRate::AssumeRate(PClip _clip, int _rate) | |
| 411 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 13 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
|
1 | : NonCachedGenericVideoFilter(_clip) { |
| 412 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
|
1 | if (_rate < 0) |
| 413 | ✗ | _rate = 0; | |
| 414 |
2/4✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 14 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
|
1 | if (vi.SamplesPerSecond() == 0) // Don't add audio if none is present. |
| 415 | ✗ | _rate = 0; | |
| 416 | |||
| 417 | 1 | vi.audio_samples_per_second = _rate; | |
| 418 | 1 | } | |
| 419 | |||
| 420 | ✗ | AVSValue __cdecl AssumeRate::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 421 | ✗ | return new AssumeRate(args[0].AsClip(), args[1].AsInt()); | |
| 422 | } | ||
| 423 | |||
| 424 | |||
| 425 | |||
| 426 | |||
| 427 | |||
| 428 | /****************************************** | ||
| 429 | ******* Convert Audio -> Mono ****** | ||
| 430 | ******* Supports int16 & float ****** | ||
| 431 | *****************************************/ | ||
| 432 | |||
| 433 | 1 | ConvertToMono::ConvertToMono(PClip _clip) : | |
| 434 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 12 not taken.
|
2 | GenericVideoFilter(ConvertAudio::Create(_clip, SAMPLE_INT16 | SAMPLE_FLOAT, SAMPLE_FLOAT)), |
| 435 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 14 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 10 not taken.
|
2 | tempbuffer(NULL) |
| 436 | { | ||
| 437 |
1/2✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 16 not taken.
|
1 | channels = vi.AudioChannels(); |
| 438 | 1 | vi.nchannels = 1; | |
| 439 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 16 not taken.
|
1 | vi.SetChannelMask(true, AvsChannelMask::MASK_SPEAKER_FRONT_CENTER); |
| 440 | 1 | tempbuffer_size = 0; | |
| 441 | 1 | } | |
| 442 | |||
| 443 | |||
| 444 | 1 | void __stdcall ConvertToMono::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 445 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 9 taken 1 time.
|
1 | if (tempbuffer_size) { |
| 446 | ✗ | if (tempbuffer_size < count) { | |
| 447 | ✗ | delete[] tempbuffer; | |
| 448 | ✗ | tempbuffer = new char[(unsigned)(count * channels * vi.BytesPerChannelSample())]; | |
| 449 | ✗ | tempbuffer_size = (int)count; | |
| 450 | } | ||
| 451 | } else { | ||
| 452 | 1 | tempbuffer = new char[(unsigned)(count * channels * vi.BytesPerChannelSample())]; | |
| 453 | 1 | tempbuffer_size = (int)count; | |
| 454 | } | ||
| 455 | |||
| 456 | 1 | child->GetAudio(tempbuffer, start, count, env); | |
| 457 | |||
| 458 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 22 taken 1 time.
|
1 | if (vi.IsSampleType(SAMPLE_INT16)) { |
| 459 | ✗ | signed short* samples = (signed short*)buf; | |
| 460 | ✗ | signed short* tempsamples = (signed short*)tempbuffer; | |
| 461 | ✗ | const int rchannels = 65536 / channels; | |
| 462 | |||
| 463 | ✗ | for (int i = 0; i < (int)count; i++) { // Defeat slow default "(int64_t)i < count" | |
| 464 | ✗ | int tsample = 0; | |
| 465 | ✗ | for (int j = 0 ; j < channels; j++) | |
| 466 | ✗ | tsample += *tempsamples++; // Accumulate samples | |
| 467 | ✗ | samples[i] = (signed short)((tsample * rchannels + 32768) >> 16); // tsample * (1/channels) + 0.5 | |
| 468 | } | ||
| 469 | } | ||
| 470 |
1/2✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 30 not taken.
|
1 | else if (vi.IsSampleType(SAMPLE_FLOAT)) { |
| 471 | 1 | SFLOAT* samples = (SFLOAT*)buf; | |
| 472 | 1 | SFLOAT* tempsamples = (SFLOAT*)tempbuffer; | |
| 473 | 1 | const SFLOAT f_rchannels = SFLOAT(1.0 / channels); | |
| 474 | |||
| 475 |
2/2✓ Branch 29 → 25 taken 2 times.
✓ Branch 29 → 30 taken 1 time.
|
3 | for (int i = 0; i < (int)count; i++) { // Defeat slow default "(int64_t)i < count" |
| 476 | 2 | SFLOAT tsample = 0.0f; | |
| 477 |
2/2✓ Branch 27 → 26 taken 6 times.
✓ Branch 27 → 28 taken 2 times.
|
8 | for (int j = 0 ; j < channels; j++) |
| 478 | 6 | tsample += *tempsamples++; // Accumulate samples | |
| 479 | 2 | samples[i] = (tsample * f_rchannels); | |
| 480 | } | ||
| 481 | } | ||
| 482 | 1 | } | |
| 483 | |||
| 484 | 1 | int __stdcall ConvertToMono::SetCacheHints(int cachehints, int frame_range) { | |
| 485 | AVS_UNUSED(frame_range); | ||
| 486 | |||
| 487 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
|
1 | switch (cachehints) { |
| 488 | 1 | case CACHE_GET_MTMODE: | |
| 489 | 1 | return MT_SERIALIZED; | |
| 490 | ✗ | default: | |
| 491 | ✗ | break; | |
| 492 | } | ||
| 493 | ✗ | return 0; | |
| 494 | } | ||
| 495 | |||
| 496 | ✗ | PClip ConvertToMono::Create(PClip clip) { | |
| 497 | ✗ | if (!clip->GetVideoInfo().HasAudio()) | |
| 498 | ✗ | return clip; | |
| 499 | ✗ | if (clip->GetVideoInfo().AudioChannels() == 1) | |
| 500 | ✗ | return clip; | |
| 501 | else | ||
| 502 | ✗ | return new ConvertToMono(clip); | |
| 503 | } | ||
| 504 | |||
| 505 | ✗ | AVSValue __cdecl ConvertToMono::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 506 | ✗ | return Create(args[0].AsClip()); | |
| 507 | } | ||
| 508 | |||
| 509 | /****************************************** | ||
| 510 | ******* Ensure VBR mp3 sync, ****** | ||
| 511 | ******* by always reading audio ****** | ||
| 512 | ******* sequencial. ****** | ||
| 513 | *****************************************/ | ||
| 514 | |||
| 515 | // EnsureVBRMP3Sync adds a 1MB audio cache and causes a high penalty for any out of order | ||
| 516 | // accesses outside the audio cache: a seek to zero plus a linear read up to the new position. | ||
| 517 | |||
| 518 | 1 | EnsureVBRMP3Sync::EnsureVBRMP3Sync(PClip _clip) | |
| 519 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
|
1 | : GenericVideoFilter(_clip) { |
| 520 | 1 | last_end = 0; | |
| 521 | 1 | } | |
| 522 | |||
| 523 | |||
| 524 | 3 | void __stdcall EnsureVBRMP3Sync::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 525 | |||
| 526 |
2/2✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 28 taken 1 time.
|
3 | if (start != last_end) { // Reread! |
| 527 | 2 | int64_t bcount = count; | |
| 528 | 2 | int64_t offset = 0; | |
| 529 | 2 | char* samples = (char*)buf; | |
| 530 | 2 | bool bigbuff=false; | |
| 531 | |||
| 532 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
|
2 | if (start > last_end) |
| 533 | 1 | offset = last_end; // Skip forward only if the skipped to position is in front of last position. | |
| 534 | |||
| 535 |
5/6✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 9 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 9 not taken.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 16 taken 1 time.
|
2 | if ((count < start-offset) && (vi.BytesFromAudioSamples(count) < BIGBUFFSIZE)) { |
| 536 | 1 | samples = new(std::nothrow) char[BIGBUFFSIZE]; | |
| 537 |
1/2✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 15 not taken.
|
1 | if (samples) { |
| 538 | 1 | bigbuff=true; | |
| 539 | 1 | bcount = vi.AudioSamplesFromBytes(BIGBUFFSIZE); | |
| 540 | } | ||
| 541 | else { | ||
| 542 | ✗ | samples = (char*)buf; // malloc failed just reuse clients buffer | |
| 543 | } | ||
| 544 | } | ||
| 545 |
1/2✗ Branch 20 → 17 not taken.
✓ Branch 20 → 21 taken 2 times.
|
2 | while (offset + bcount < start) { // Read whole blocks of 'bcount' samples |
| 546 | ✗ | child->GetAudio(samples, offset, bcount, env); | |
| 547 | ✗ | offset += bcount; | |
| 548 | } // Read until 'start' | ||
| 549 | 2 | child->GetAudio(samples, offset, start - offset, env); // Now we're at 'start' | |
| 550 | 2 | offset += start - offset; | |
| 551 |
3/4✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 26 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✗ Branch 24 → 26 not taken.
|
2 | if (bigbuff) delete[] samples; |
| 552 |
1/2✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 2 times.
|
2 | if (offset != start) |
| 553 | ✗ | env->ThrowError("EnsureVBRMP3Sync [Internal error]: Offset should be %i, but is %i", start, offset); | |
| 554 | } | ||
| 555 | 3 | child->GetAudio(buf, start, count, env); | |
| 556 | 3 | last_end = start + count; | |
| 557 | 3 | } | |
| 558 | |||
| 559 | |||
| 560 | 3 | int __stdcall EnsureVBRMP3Sync::SetCacheHints(int cachehints, int frame_range) { | |
| 561 | AVS_UNUSED(frame_range); | ||
| 562 | // Enable CACHE_AUDIO on parent cache and juice it up to 1Mb | ||
| 563 | |||
| 564 |
3/4✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 2 → 5 taken 1 time.
✗ Branch 2 → 6 not taken.
|
3 | switch (cachehints) { |
| 565 | 1 | case CACHE_GET_MTMODE: | |
| 566 | 1 | return MT_SERIALIZED; | |
| 567 | |||
| 568 | 1 | case CACHE_GETCHILD_AUDIO_MODE: // Parent Cache asking Child for desired audio cache mode | |
| 569 | 1 | return CACHE_AUDIO; | |
| 570 | |||
| 571 | 1 | case CACHE_GETCHILD_AUDIO_SIZE: // Parent Cache asking Child for desired audio cache size | |
| 572 | 1 | return 1024*1024; | |
| 573 | |||
| 574 | ✗ | default: | |
| 575 | ✗ | break; | |
| 576 | } | ||
| 577 | ✗ | return 0; | |
| 578 | } | ||
| 579 | |||
| 580 | ✗ | AVSValue __cdecl EnsureVBRMP3Sync::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 581 | ✗ | return new EnsureVBRMP3Sync(args[0].AsClip()); | |
| 582 | } | ||
| 583 | |||
| 584 | |||
| 585 | /******************************************* | ||
| 586 | ******* Mux 'N' sources, so the **** | ||
| 587 | ******* total channels is the sum of **** | ||
| 588 | ******* the channels in the 'N' clip **** | ||
| 589 | *******************************************/ | ||
| 590 | |||
| 591 | 1 | MergeChannels::MergeChannels(PClip _clip, int _num_children, PClip* _child_array, IScriptEnvironment* env) : | |
| 592 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 45 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 43 not taken.
|
1 | GenericVideoFilter(_clip), tempbuffer(NULL), child_array(_child_array), num_children(_num_children) |
| 593 | { | ||
| 594 |
2/4✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 55 not taken.
|
1 | clip_channels = new int[num_children]; |
| 595 |
2/4✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 11 not taken.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 55 not taken.
|
1 | clip_offset = new signed char * [num_children]; |
| 596 |
1/2✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 55 not taken.
|
1 | clip_channels[0] = vi.AudioChannels(); |
| 597 | |||
| 598 |
2/2✓ Branch 35 → 15 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
|
2 | for (int i = 1;i < num_children;i++) { |
| 599 |
1/2✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 54 not taken.
|
1 | PClip tclip = child_array[i]; |
| 600 |
5/10✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 51 not taken.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 51 not taken.
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 50 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 48 not taken.
✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 46 not taken.
|
1 | child_array[i] = ConvertAudio::Create(tclip, vi.SampleType(), vi.SampleType()); // Clip 2 should now be same type as clip 1. |
| 601 |
1/2✓ Branch 24 → 25 taken 1 time.
✗ Branch 24 → 52 not taken.
|
1 | const VideoInfo& vi2 = child_array[i]->GetVideoInfo(); |
| 602 | |||
| 603 |
1/2✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 1 time.
|
1 | if (vi.audio_samples_per_second != vi2.audio_samples_per_second) { |
| 604 | ✗ | env->ThrowError("MergeChannels: Clips must have same sample rate! Use ResampleAudio()!"); // Could be removed for fun :) | |
| 605 | } | ||
| 606 |
3/6✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 52 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 52 not taken.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 1 time.
|
1 | if (vi.SampleType() != vi2.SampleType()) |
| 607 | ✗ | env->ThrowError("MergeChannels: Clips must have same sample type! Use ConvertAudio()!"); // Should never happend! | |
| 608 |
1/2✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 52 not taken.
|
1 | clip_channels[i] = vi2.AudioChannels(); |
| 609 |
1/2✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 52 not taken.
|
1 | vi.nchannels += vi2.AudioChannels(); |
| 610 | 1 | } | |
| 611 | |||
| 612 |
2/4✓ Branch 36 → 37 taken 1 time.
✗ Branch 36 → 55 not taken.
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 41 not taken.
|
1 | if (vi.AudioChannels() <= 8) |
| 613 |
2/4✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 55 not taken.
✓ Branch 40 → 42 taken 1 time.
✗ Branch 40 → 55 not taken.
|
1 | vi.SetChannelMask(true, GetDefaultChannelLayout(vi.AudioChannels())); |
| 614 | else | ||
| 615 | ✗ | vi.SetChannelMask(false, 0); // over 8: no guess | |
| 616 | |||
| 617 | 1 | tempbuffer_size = 0; | |
| 618 | 1 | } | |
| 619 | |||
| 620 | 1 | MergeChannels::~MergeChannels() { | |
| 621 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 6 not taken.
|
1 | if (tempbuffer_size) { |
| 622 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
|
1 | delete[] tempbuffer; |
| 623 | 1 | tempbuffer_size=0; | |
| 624 | } | ||
| 625 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
|
1 | delete[] clip_channels; |
| 626 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
|
1 | delete[] clip_offset; |
| 627 |
3/4✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 15 not taken.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 1 time.
|
3 | delete[] child_array; |
| 628 | 1 | } | |
| 629 | |||
| 630 | |||
| 631 | 1 | void __stdcall MergeChannels::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 632 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 9 not taken.
|
1 | if (tempbuffer_size < count) { |
| 633 |
1/4✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 1 time.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
|
1 | if (tempbuffer_size) delete[] tempbuffer; |
| 634 | 1 | tempbuffer = new signed char[(unsigned)(count * vi.BytesPerAudioSample())]; | |
| 635 | 1 | tempbuffer_size = (int)count; | |
| 636 | } | ||
| 637 | // Get audio: | ||
| 638 | 1 | const int channel_offset = (int)count * vi.BytesPerChannelSample(); // Offset per channel | |
| 639 | 1 | int i, c_channel = 0; | |
| 640 | |||
| 641 |
2/2✓ Branch 14 → 11 taken 2 times.
✓ Branch 14 → 15 taken 1 time.
|
3 | for (i = 0;i < num_children;i++) { |
| 642 | 2 | child_array[i]->GetAudio(tempbuffer + (c_channel*channel_offset), start, count, env); | |
| 643 | 2 | clip_offset[i] = tempbuffer + (c_channel * channel_offset); | |
| 644 | 2 | c_channel += clip_channels[i]; | |
| 645 | } | ||
| 646 | |||
| 647 | // Interleave channels | ||
| 648 | 1 | char* samples = (char*) buf; | |
| 649 | 1 | const int bpcs = vi.BytesPerChannelSample(); | |
| 650 | 1 | const int bps = vi.BytesPerAudioSample(); | |
| 651 | 1 | int dst_offset = 0; | |
| 652 |
2/2✓ Branch 38 → 18 taken 2 times.
✓ Branch 38 → 39 taken 1 time.
|
3 | for (i = 0;i < num_children;i++) { |
| 653 | 2 | signed char* src_buf = clip_offset[i]; | |
| 654 | 2 | const int bpcc = bpcs*clip_channels[i]; | |
| 655 | |||
| 656 |
1/4✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 23 not taken.
✗ Branch 18 → 27 not taken.
✗ Branch 18 → 31 not taken.
|
2 | switch (bpcc) { |
| 657 | |||
| 658 | 2 | case 2: { // mono 16 bit | |
| 659 |
2/2✓ Branch 21 → 20 taken 6 times.
✓ Branch 21 → 22 taken 2 times.
|
8 | for (int l = 0, k=dst_offset; l < count; l++, k+=bps) { |
| 660 | 6 | *(short*)(samples+k) = ((short*)src_buf)[l]; | |
| 661 | } | ||
| 662 | 2 | break; | |
| 663 | } | ||
| 664 | ✗ | case 4: { // mono float/32 bit, stereo 16 bit | |
| 665 | ✗ | for (int l = 0, k=dst_offset; l < count; l++, k+=bps) { | |
| 666 | ✗ | *(int*)(samples+k) = ((int*)src_buf)[l]; | |
| 667 | } | ||
| 668 | ✗ | break; | |
| 669 | } | ||
| 670 | ✗ | case 8: { // stereo float/32 bit | |
| 671 | #ifdef INTEL_INTRINSICS | ||
| 672 | #if defined(X86_32) && defined(MSVC) | ||
| 673 | if (env->GetCPUFlags() & CPUF_MMX) | ||
| 674 | { | ||
| 675 | __asm | ||
| 676 | { | ||
| 677 | mov eax,[src_buf] | ||
| 678 | mov edi,[samples] | ||
| 679 | mov ecx,dword ptr[count] | ||
| 680 | add edi,[dst_offset] | ||
| 681 | test ecx,ecx | ||
| 682 | mov edx,[bps] ; bytes per strip | ||
| 683 | jz done | ||
| 684 | shr ecx,1 ; CF=count&1, count>>=1 | ||
| 685 | jnc label ; count was even | ||
| 686 | |||
| 687 | movq mm1,[eax] ; do 1 odd quad | ||
| 688 | add eax,8 | ||
| 689 | movq [edi],mm1 | ||
| 690 | add edi,edx | ||
| 691 | test ecx,ecx | ||
| 692 | jz done | ||
| 693 | align 16 | ||
| 694 | label: | ||
| 695 | movq mm0,[eax] ; do pairs of quads | ||
| 696 | movq mm1,[eax+8] | ||
| 697 | add eax,16 | ||
| 698 | movq [edi],mm0 | ||
| 699 | movq [edi+edx],mm1 | ||
| 700 | lea edi,[edi+edx*2] | ||
| 701 | loop label | ||
| 702 | done: | ||
| 703 | emms | ||
| 704 | } | ||
| 705 | } | ||
| 706 | else | ||
| 707 | #endif // X86_32 | ||
| 708 | #endif | ||
| 709 | { | ||
| 710 | ✗ | for (int l = 0, k=dst_offset; l < count; l++, k+=bps) | |
| 711 | { | ||
| 712 | ✗ | *(int64_t*)(samples+k) = ((int64_t*)src_buf)[l]; | |
| 713 | } | ||
| 714 | } | ||
| 715 | ✗ | break; | |
| 716 | } | ||
| 717 | ✗ | default: { // everything else, 1 byte at a time | |
| 718 | ✗ | for (int l = 0; l < count; l++) { | |
| 719 | ✗ | for (int k = 0; k < bpcc; k++) { | |
| 720 | ✗ | samples[dst_offset + (l*bps) + k] = src_buf[(l*bpcc) + k]; | |
| 721 | } | ||
| 722 | } | ||
| 723 | } | ||
| 724 | } | ||
| 725 | 2 | dst_offset += bpcc; | |
| 726 | } | ||
| 727 | 1 | } | |
| 728 | |||
| 729 | 1 | int __stdcall MergeChannels::SetCacheHints(int cachehints, int frame_range) { | |
| 730 | AVS_UNUSED(frame_range); | ||
| 731 | |||
| 732 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
|
1 | switch (cachehints) { |
| 733 | 1 | case CACHE_GET_MTMODE: | |
| 734 | 1 | return MT_SERIALIZED; | |
| 735 | ✗ | default: | |
| 736 | ✗ | break; | |
| 737 | } | ||
| 738 | ✗ | return 0; | |
| 739 | } | ||
| 740 | |||
| 741 | ✗ | AVSValue __cdecl MergeChannels::Create(AVSValue args, void*, IScriptEnvironment* env) { | |
| 742 | int num_args; | ||
| 743 | PClip* child_array; | ||
| 744 | |||
| 745 | ✗ | if (args[0].IsArray()) { | |
| 746 | ✗ | num_args = args[0].ArraySize(); | |
| 747 | ✗ | if (num_args == 1) | |
| 748 | ✗ | return args[0][0]; | |
| 749 | |||
| 750 | ✗ | child_array = new PClip[num_args]; | |
| 751 | ✗ | for (int i = 0; i < num_args; ++i) | |
| 752 | ✗ | child_array[i] = args[0][i].AsClip(); | |
| 753 | |||
| 754 | ✗ | return new MergeChannels(args[0][0].AsClip(), num_args, child_array, env); | |
| 755 | } | ||
| 756 | // MonoToStereo Case | ||
| 757 | ✗ | num_args = 2; | |
| 758 | ✗ | child_array = new PClip[num_args]; | |
| 759 | ✗ | child_array[0] = GetChannel::Create_left(args[0].AsClip()); | |
| 760 | ✗ | child_array[1] = GetChannel::Create_right(args[1].AsClip()); | |
| 761 | |||
| 762 | ✗ | return new MergeChannels(child_array[0], num_args, child_array, env); | |
| 763 | } | ||
| 764 | |||
| 765 | |||
| 766 | /*************************************************** | ||
| 767 | ******* Get left or right ******* | ||
| 768 | ******* channel from a stereo source ******* | ||
| 769 | ***************************************************/ | ||
| 770 | |||
| 771 | |||
| 772 | |||
| 773 | 1 | GetChannel::GetChannel(PClip _clip, int* _channel, int _numchannels) : | |
| 774 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 15 not taken.
|
1 | GenericVideoFilter(_clip), tempbuffer(NULL), channel(_channel), numchannels(_numchannels) |
| 775 | { | ||
| 776 |
1/2✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 18 not taken.
|
1 | cbps = vi.BytesPerChannelSample(); |
| 777 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 18 not taken.
|
1 | src_bps = vi.BytesPerAudioSample(); |
| 778 | 1 | vi.nchannels = numchannels; | |
| 779 | 1 | tempbuffer_size = 0; | |
| 780 |
1/2✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 18 not taken.
|
1 | dst_bps = vi.BytesPerAudioSample(); |
| 781 | |||
| 782 |
2/4✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 18 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 13 not taken.
|
1 | if (vi.AudioChannels() <= 8) |
| 783 |
2/4✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 14 taken 1 time.
✗ Branch 12 → 18 not taken.
|
1 | vi.SetChannelMask(true, GetDefaultChannelLayout(vi.AudioChannels())); |
| 784 | else | ||
| 785 | ✗ | vi.SetChannelMask(false, 0); // over 8: no guess | |
| 786 | 1 | } | |
| 787 | |||
| 788 | |||
| 789 | 1 | void __stdcall GetChannel::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 790 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
|
1 | if (tempbuffer_size < count) { |
| 791 |
1/4✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 1 time.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
|
1 | if (tempbuffer_size) delete[] tempbuffer; |
| 792 | 1 | tempbuffer = new char[(unsigned)(count * src_bps)]; | |
| 793 | 1 | tempbuffer_size = (int)count; | |
| 794 | } | ||
| 795 | 1 | child->GetAudio(tempbuffer, start, count, env); | |
| 796 | |||
| 797 |
1/4✗ Branch 10 → 11 not taken.
✓ Branch 10 → 18 taken 1 time.
✗ Branch 10 → 25 not taken.
✗ Branch 10 → 32 not taken.
|
1 | switch (cbps) { |
| 798 | ✗ | case 1: { // 8 bit | |
| 799 | ✗ | char* samples = (char*)buf; | |
| 800 | ✗ | char* tbuff = tempbuffer; | |
| 801 | ✗ | for (int i = 0; i < count; i++) { | |
| 802 | ✗ | for (int k = 0; k < numchannels; k++) { | |
| 803 | ✗ | *(samples++) = tbuff[channel[k]]; | |
| 804 | } | ||
| 805 | ✗ | tbuff += src_bps; | |
| 806 | } | ||
| 807 | ✗ | break; | |
| 808 | } | ||
| 809 | 1 | case 2: { // 16 bit | |
| 810 | 1 | short* samples = (short*)buf; | |
| 811 | 1 | short* tbuff = (short*)tempbuffer; | |
| 812 |
2/2✓ Branch 23 → 19 taken 3 times.
✓ Branch 23 → 24 taken 1 time.
|
4 | for (int i = 0; i < count; i++) { |
| 813 |
2/2✓ Branch 21 → 20 taken 6 times.
✓ Branch 21 → 22 taken 3 times.
|
9 | for (int k = 0; k < numchannels; k++) { |
| 814 | 6 | *(samples++) = tbuff[channel[k]]; | |
| 815 | } | ||
| 816 | 3 | tbuff += src_bps>>1; | |
| 817 | } | ||
| 818 | 1 | break; | |
| 819 | } | ||
| 820 | ✗ | case 4: { // float/32 bit | |
| 821 | ✗ | int* samples = (int*)buf; | |
| 822 | ✗ | int* tbuff = (int*)tempbuffer; | |
| 823 | ✗ | for (int i = 0; i < count; i++) { | |
| 824 | ✗ | for (int k = 0; k < numchannels; k++) { | |
| 825 | ✗ | *(samples++) = tbuff[channel[k]]; | |
| 826 | } | ||
| 827 | ✗ | tbuff += src_bps>>2; | |
| 828 | } | ||
| 829 | ✗ | break; | |
| 830 | } | ||
| 831 | ✗ | default: { // 24 bit, etc | |
| 832 | ✗ | char* samples = (char*)buf; | |
| 833 | ✗ | char* tbuff = tempbuffer; | |
| 834 | ✗ | for (int i = 0; i < count; i++) { | |
| 835 | ✗ | for (int k = 0; k < numchannels; k++) { | |
| 836 | ✗ | int src_o = channel[k] * cbps; | |
| 837 | ✗ | for (int j = src_o; j < src_o+cbps; j++) | |
| 838 | ✗ | *(samples++) = tbuff[j]; | |
| 839 | } | ||
| 840 | ✗ | tbuff += src_bps; | |
| 841 | } | ||
| 842 | ✗ | break; | |
| 843 | } | ||
| 844 | } | ||
| 845 | 1 | } | |
| 846 | |||
| 847 | 1 | int __stdcall GetChannel::SetCacheHints(int cachehints, int frame_range) { | |
| 848 | AVS_UNUSED(frame_range); | ||
| 849 | |||
| 850 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
|
1 | switch (cachehints) { |
| 851 | 1 | case CACHE_GET_MTMODE: | |
| 852 | 1 | return MT_SERIALIZED; | |
| 853 | ✗ | default: | |
| 854 | ✗ | break; | |
| 855 | } | ||
| 856 | ✗ | return 0; | |
| 857 | } | ||
| 858 | |||
| 859 | ✗ | PClip GetChannel::Create_left(PClip clip) { | |
| 860 | |||
| 861 | ✗ | if (clip->GetVideoInfo().AudioChannels() != 1) { | |
| 862 | ✗ | int* ch = new int[1]; | |
| 863 | ✗ | ch[0] = 0; | |
| 864 | ✗ | clip = new GetChannel(clip, ch, 1); | |
| 865 | } | ||
| 866 | // do not preserve 'left'ness | ||
| 867 | ✗ | return new SetChannelMask(clip, true, AvsChannelMask::MASK_SPEAKER_FRONT_CENTER); | |
| 868 | } | ||
| 869 | |||
| 870 | ✗ | PClip GetChannel::Create_right(PClip clip) { | |
| 871 | ✗ | if (clip->GetVideoInfo().AudioChannels() != 1) | |
| 872 | { | ||
| 873 | ✗ | int* ch = new int[1]; | |
| 874 | ✗ | ch[0] = 1; | |
| 875 | ✗ | clip = new GetChannel(clip, ch, 1); | |
| 876 | } | ||
| 877 | // do not preserve 'right'ness | ||
| 878 | ✗ | return new SetChannelMask(clip, true, AvsChannelMask::MASK_SPEAKER_FRONT_CENTER); | |
| 879 | } | ||
| 880 | |||
| 881 | ✗ | PClip GetChannel::Create_n(PClip clip, int* n, int numchannels) { | |
| 882 | ✗ | return new GetChannel(clip, n, numchannels); | |
| 883 | } | ||
| 884 | |||
| 885 | ✗ | AVSValue __cdecl GetChannel::Create_left(AVSValue args, void*, IScriptEnvironment*) { | |
| 886 | ✗ | return Create_left(args[0].AsClip()); | |
| 887 | } | ||
| 888 | |||
| 889 | ✗ | AVSValue __cdecl GetChannel::Create_right(AVSValue args, void*, IScriptEnvironment*) { | |
| 890 | ✗ | return Create_right(args[0].AsClip()); | |
| 891 | } | ||
| 892 | |||
| 893 | ✗ | AVSValue __cdecl GetChannel::Create_n(AVSValue args, void*, IScriptEnvironment* env) { | |
| 894 | ✗ | AVSValue args_c = args[1]; | |
| 895 | ✗ | const int num_args = args_c.ArraySize(); | |
| 896 | ✗ | int* child_array = new int[num_args]; | |
| 897 | ✗ | for (int i = 0; i < num_args; ++i) { | |
| 898 | ✗ | child_array[i] = args_c[i].AsInt() - 1; // Beware: Channel is 0-based in code and 1 based in scripts | |
| 899 | ✗ | if (child_array[i] >= args[0].AsClip()->GetVideoInfo().AudioChannels()) | |
| 900 | ✗ | env->ThrowError("GetChannel: Attempted to request a channel that didn't exist!"); | |
| 901 | ✗ | if (child_array[i] < 0) | |
| 902 | ✗ | env->ThrowError("GetChannel: There are no channels below 1! (first channel is 1)"); | |
| 903 | } | ||
| 904 | ✗ | return Create_n(args[0].AsClip(), child_array, num_args); | |
| 905 | ✗ | } | |
| 906 | |||
| 907 | /****************************** | ||
| 908 | ******* Kill Video ******** | ||
| 909 | ******************************/ | ||
| 910 | |||
| 911 | 1 | KillVideo::KillVideo(PClip _clip) | |
| 912 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
|
1 | : GenericVideoFilter(_clip) { |
| 913 | 1 | vi.width = 0; | |
| 914 | 1 | vi.height= 0; | |
| 915 | 1 | vi.fps_numerator = 0; | |
| 916 | 1 | vi.fps_denominator= 0; | |
| 917 | 1 | vi.num_frames = 0; | |
| 918 | 1 | vi.pixel_type = 0; | |
| 919 | 1 | vi.image_type = 0; | |
| 920 | 1 | } | |
| 921 | |||
| 922 | ✗ | AVSValue __cdecl KillVideo::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 923 | ✗ | return new KillVideo(args[0].AsClip()); | |
| 924 | } | ||
| 925 | |||
| 926 | |||
| 927 | /****************************** | ||
| 928 | ******* Kill Audio ******** | ||
| 929 | ******************************/ | ||
| 930 | |||
| 931 | 1 | KillAudio::KillAudio(PClip _clip) | |
| 932 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 7 not taken.
|
1 | : NonCachedGenericVideoFilter(_clip) { |
| 933 | 1 | vi.audio_samples_per_second = 0; | |
| 934 | 1 | vi.sample_type = 0; | |
| 935 | 1 | vi.num_audio_samples = 0; | |
| 936 | 1 | vi.nchannels = 0; | |
| 937 |
1/2✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 10 not taken.
|
1 | vi.SetChannelMask(false, 0); |
| 938 | 1 | } | |
| 939 | |||
| 940 | ✗ | AVSValue __cdecl KillAudio::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 941 | ✗ | return new KillAudio(args[0].AsClip()); | |
| 942 | } | ||
| 943 | |||
| 944 | /****************************** | ||
| 945 | ****** Set Channel Mask ****** | ||
| 946 | ******************************/ | ||
| 947 | |||
| 948 | 2 | SetChannelMask::SetChannelMask(PClip _clip, bool IsChannelMaskKnown, unsigned int dwChannelMask) | |
| 949 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 7 not taken.
|
2 | : NonCachedGenericVideoFilter(_clip) { |
| 950 |
1/2✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 10 not taken.
|
2 | vi.SetChannelMask(IsChannelMaskKnown, dwChannelMask); |
| 951 | 2 | } | |
| 952 | |||
| 953 | ✗ | AVSValue __cdecl SetChannelMask::Create(AVSValue args, void*, IScriptEnvironment* env) { | |
| 954 | ✗ | if (args[1].IsString()) { | |
| 955 | ✗ | const char* channelName = args[1].AsString(""); | |
| 956 | ✗ | if (*channelName) { | |
| 957 | ✗ | unsigned int channelMask = av_get_channel_layout(channelName); | |
| 958 | ✗ | if (channelMask == 0) | |
| 959 | ✗ | env->ThrowError("SetChannelMask: could not find channel descriptor/combo '%s'\n", channelName); | |
| 960 | ✗ | return new SetChannelMask(args[0].AsClip(), true, channelMask); | |
| 961 | } | ||
| 962 | // fallthrough, "" given -> unknown | ||
| 963 | } | ||
| 964 | else { | ||
| 965 | ✗ | const bool known = args[1].AsBool(false); | |
| 966 | ✗ | if (known) | |
| 967 | ✗ | return new SetChannelMask(args[0].AsClip(), true, args[2].AsInt(0)); | |
| 968 | } | ||
| 969 | ✗ | return new SetChannelMask(args[0].AsClip(), false, 0); | |
| 970 | } | ||
| 971 | |||
| 972 | |||
| 973 | /****************************** | ||
| 974 | ******* Delay Audio ****** | ||
| 975 | *****************************/ | ||
| 976 | |||
| 977 | 1 | DelayAudio::DelayAudio(double delay, PClip _child) | |
| 978 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
|
1 | : GenericVideoFilter(_child), delay_samples(int64_t(delay * vi.audio_samples_per_second + 0.5)) { |
| 979 | 1 | vi.num_audio_samples += delay_samples; | |
| 980 | 1 | } | |
| 981 | |||
| 982 | |||
| 983 | 1 | void DelayAudio::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 984 | 1 | child->GetAudio(buf, start - delay_samples, count, env); | |
| 985 | 1 | } | |
| 986 | |||
| 987 | |||
| 988 | ✗ | AVSValue __cdecl DelayAudio::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 989 | ✗ | return new DelayAudio(args[1].AsFloat(), args[0].AsClip()); | |
| 990 | } | ||
| 991 | |||
| 992 | |||
| 993 | /******************************** | ||
| 994 | ******* Amplify Audio ****** | ||
| 995 | *******************************/ | ||
| 996 | |||
| 997 | |||
| 998 | 2 | Amplify::Amplify(PClip _child, float* _volumes, int* _i_v) | |
| 999 |
1/2✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 10 not taken.
|
4 | : GenericVideoFilter(ConvertAudio::Create(_child, SAMPLE_INT16 | SAMPLE_FLOAT | SAMPLE_INT32, SAMPLE_FLOAT)), |
| 1000 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 12 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 8 not taken.
|
6 | volumes(_volumes), i_v(_i_v) { } |
| 1001 | |||
| 1002 | |||
| 1003 | 2 | Amplify::~Amplify() | |
| 1004 | { | ||
| 1005 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 5 not taken.
|
2 | if (volumes) { delete[] (float*)volumes; volumes=0; } |
| 1006 |
2/4✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 10 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 9 not taken.
|
2 | if (i_v) { delete[] (int*)i_v; i_v=0; } |
| 1007 | 2 | } | |
| 1008 | |||
| 1009 | |||
| 1010 | 2 | void __stdcall Amplify::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 1011 | 2 | child->GetAudio(buf, start, count, env); | |
| 1012 | 2 | int channels = vi.AudioChannels(); | |
| 1013 | 2 | int countXchannels = (int)count*channels; | |
| 1014 | |||
| 1015 |
2/2✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 16 taken 1 time.
|
2 | if (vi.SampleType() == SAMPLE_INT16) { |
| 1016 | #if defined(X86_32) && defined(MSVC) | ||
| 1017 | const short* endsample = (short*)buf + countXchannels; | ||
| 1018 | const int* iv = i_v; | ||
| 1019 | |||
| 1020 | __asm { | ||
| 1021 | mov ecx, [iv] | ||
| 1022 | mov edi, [buf] | ||
| 1023 | align 16 | ||
| 1024 | iloop0: | ||
| 1025 | xor esi, esi ; j | ||
| 1026 | jloop0: | ||
| 1027 | mov eax, DWORD PTR [ecx+esi*4] ; i_v[j] | ||
| 1028 | movsx edx, WORD PTR [edi] ; *samples | ||
| 1029 | inc esi ; j++ | ||
| 1030 | imul edx | ||
| 1031 | add edi, 2 ; samples++ | ||
| 1032 | add eax, 65536 | ||
| 1033 | adc edx, 0 | ||
| 1034 | |||
| 1035 | cmp edx, -1 ; if (nh < -1) return MIN_SHORT; | ||
| 1036 | jge notnegsat0 | ||
| 1037 | mov eax, -32768 | ||
| 1038 | jmp saturate0 | ||
| 1039 | notnegsat0: | ||
| 1040 | test edx, edx ; if (nh > 0) return MAX_SHORT; | ||
| 1041 | jle notpossat0 | ||
| 1042 | mov eax, 32767 | ||
| 1043 | jmp saturate0 | ||
| 1044 | notpossat0: | ||
| 1045 | shrd eax, edx, 17 ; n>>17 | ||
| 1046 | saturate0: | ||
| 1047 | mov WORD PTR [edi-2], ax ; *samples | ||
| 1048 | cmp esi, [channels] ; j < channels | ||
| 1049 | jl jloop0 | ||
| 1050 | |||
| 1051 | cmp edi, [endsample] | ||
| 1052 | jl iloop0 | ||
| 1053 | } | ||
| 1054 | #else | ||
| 1055 | 1 | short* samples = (short*)buf; | |
| 1056 |
2/2✓ Branch 14 → 8 taken 3 times.
✓ Branch 14 → 15 taken 1 time.
|
4 | for (int i = 0; i < countXchannels; i+=channels) { |
| 1057 |
2/2✓ Branch 12 → 9 taken 6 times.
✓ Branch 12 → 13 taken 3 times.
|
9 | for (int j = 0; j < channels; j++) { |
| 1058 | 6 | samples[i + j] = (short)clamp( | |
| 1059 | 6 | signed_saturated_add64(Int32x32To64(samples[i + j], i_v[j]), 65536) >> 17, | |
| 1060 | (int64_t)INT16_MIN, | ||
| 1061 | (int64_t)INT16_MAX); | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | #endif // X86_32 | ||
| 1065 | |||
| 1066 | 1 | return ; | |
| 1067 | } | ||
| 1068 | |||
| 1069 |
1/2✗ Branch 17 → 18 not taken.
✓ Branch 17 → 27 taken 1 time.
|
1 | if (vi.SampleType() == SAMPLE_INT32) { |
| 1070 | #if defined(X86_32) && defined(MSVC) | ||
| 1071 | const int* endsample = (int*)buf + countXchannels; | ||
| 1072 | const int* iv = i_v; | ||
| 1073 | |||
| 1074 | __asm { | ||
| 1075 | mov ecx, [iv] | ||
| 1076 | mov edi, [buf] | ||
| 1077 | align 16 | ||
| 1078 | iloop1: | ||
| 1079 | xor esi, esi ; j | ||
| 1080 | jloop1: | ||
| 1081 | mov eax, DWORD PTR [ecx+esi*4] ; i_v[j] | ||
| 1082 | mov edx, DWORD PTR [edi] ; *samples | ||
| 1083 | inc esi ; j++ | ||
| 1084 | imul edx | ||
| 1085 | add edi, 4 ; samples++ | ||
| 1086 | add eax, 65536 | ||
| 1087 | adc edx, 0 | ||
| 1088 | |||
| 1089 | cmp edx,0xffff0000 ; if (nh < -65536) return MIN_INT; | ||
| 1090 | jge notnegsat1 | ||
| 1091 | mov eax, 0x80000000 | ||
| 1092 | jmp saturate1 | ||
| 1093 | notnegsat1: | ||
| 1094 | cmp edx,0x0000ffff ; if (nh > 65535) return MAX_INT; | ||
| 1095 | jle notpossat1 | ||
| 1096 | mov eax, 0x7fffffff | ||
| 1097 | jmp saturate1 | ||
| 1098 | notpossat1: | ||
| 1099 | shrd eax, edx, 17 ; n>>17 | ||
| 1100 | saturate1: | ||
| 1101 | mov DWORD PTR [edi-4], eax ; *samples | ||
| 1102 | cmp esi, [channels] ; j < channels | ||
| 1103 | jl jloop1 | ||
| 1104 | |||
| 1105 | cmp edi, [endsample] | ||
| 1106 | jl iloop1 | ||
| 1107 | } | ||
| 1108 | #else | ||
| 1109 | ✗ | int* samples = (int*)buf; | |
| 1110 | ✗ | for (int i = 0; i < countXchannels; i+=channels) { | |
| 1111 | ✗ | for (int j = 0;j < channels;j++) { | |
| 1112 | ✗ | samples[i + j] = (int)clamp( | |
| 1113 | ✗ | signed_saturated_add64(Int32x32To64(samples[i + j], i_v[j]), 65536) >> 17, | |
| 1114 | (int64_t)INT32_MIN, | ||
| 1115 | (int64_t)INT32_MAX); | ||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | #endif // X86_32 | ||
| 1119 | |||
| 1120 | ✗ | return ; | |
| 1121 | } | ||
| 1122 |
1/2✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 36 not taken.
|
1 | if (vi.SampleType() == SAMPLE_FLOAT) { |
| 1123 | 1 | SFLOAT* samples = (SFLOAT*)buf; | |
| 1124 |
2/2✓ Branch 34 → 30 taken 2 times.
✓ Branch 34 → 35 taken 1 time.
|
3 | for (int i = 0; i < countXchannels; i+=channels) { |
| 1125 |
2/2✓ Branch 32 → 31 taken 4 times.
✓ Branch 32 → 33 taken 2 times.
|
6 | for (int j = 0;j < channels;j++) { // Does not saturate, as other filters do. |
| 1126 | 4 | samples[i + j] = samples[i + j] * volumes[j]; // We should saturate only on conversion. | |
| 1127 | } | ||
| 1128 | } | ||
| 1129 | 1 | return ; | |
| 1130 | } | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | |||
| 1134 | ✗ | AVSValue __cdecl Amplify::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 1135 | ✗ | if (!args[0].AsClip()->GetVideoInfo().AudioChannels()) | |
| 1136 | ✗ | return args[0]; | |
| 1137 | ✗ | AVSValue args_c = args[1]; | |
| 1138 | ✗ | const int num_args = args_c.ArraySize(); | |
| 1139 | ✗ | const int ch = args[0].AsClip()->GetVideoInfo().AudioChannels(); | |
| 1140 | ✗ | float* child_array = new float[ch]; | |
| 1141 | ✗ | int* i_child_array = new int[ch]; | |
| 1142 | ✗ | for (int i = 0; i < ch; ++i) { | |
| 1143 | ✗ | child_array[i] = args_c[min(i, num_args - 1)].AsFloatf(); | |
| 1144 | ✗ | i_child_array[i] = int(child_array[i] * 131072.0f + 0.5f); | |
| 1145 | |||
| 1146 | } | ||
| 1147 | ✗ | return new Amplify(args[0].AsClip(), child_array, i_child_array); | |
| 1148 | ✗ | } | |
| 1149 | |||
| 1150 | |||
| 1151 | |||
| 1152 | ✗ | AVSValue __cdecl Amplify::Create_dB(AVSValue args, void*, IScriptEnvironment*) { | |
| 1153 | ✗ | if (!args[0].AsClip()->GetVideoInfo().AudioChannels()) | |
| 1154 | ✗ | return args[0]; | |
| 1155 | ✗ | AVSValue args_c = args[1]; | |
| 1156 | ✗ | const int num_args = args_c.ArraySize(); | |
| 1157 | ✗ | const int ch = args[0].AsClip()->GetVideoInfo().AudioChannels(); | |
| 1158 | ✗ | float* child_array = new float[ch]; | |
| 1159 | ✗ | int* i_child_array = new int[ch]; | |
| 1160 | ✗ | for (int i = 0; i < ch; ++i) { | |
| 1161 | ✗ | child_array[i] = dBtoScaleFactorf(args_c[min(i, num_args - 1)].AsFloatf()); | |
| 1162 | ✗ | i_child_array[i] = int(child_array[i] * 131072.0f + 0.5f); | |
| 1163 | |||
| 1164 | } | ||
| 1165 | ✗ | return new Amplify(args[0].AsClip(), child_array, i_child_array); | |
| 1166 | ✗ | } | |
| 1167 | |||
| 1168 | |||
| 1169 | /***************************** | ||
| 1170 | ***** Normalize audio ****** | ||
| 1171 | ***** Supports int16,float****** | ||
| 1172 | ******************************/ | ||
| 1173 | |||
| 1174 | 2 | Normalize::Normalize(PClip _child, float _max_factor, bool _showvalues) : | |
| 1175 |
1/2✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 10 not taken.
|
4 | GenericVideoFilter(ConvertAudio::Create(_child, SAMPLE_INT16 | SAMPLE_FLOAT, SAMPLE_FLOAT)), |
| 1176 | 2 | max_factor(_max_factor), | |
| 1177 | 2 | max_volume(-1.0f), | |
| 1178 | 2 | frameno(0), | |
| 1179 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 12 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 8 not taken.
|
4 | showvalues(_showvalues) |
| 1180 | { | ||
| 1181 | 2 | } | |
| 1182 | |||
| 1183 | |||
| 1184 | |||
| 1185 | 2 | void __stdcall Normalize::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 1186 |
1/2✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 84 not taken.
|
2 | if (max_volume < 0.0f) { |
| 1187 | // Read samples into buffer and test them | ||
| 1188 |
2/2✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 50 taken 1 time.
|
2 | if (vi.SampleType() == SAMPLE_INT16) { |
| 1189 | 1 | int64_t bcount = count; | |
| 1190 | 1 | short* samples = (short*)buf; | |
| 1191 | 1 | bool bigbuff=false; | |
| 1192 | |||
| 1193 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 12 not taken.
|
1 | if (vi.BytesFromAudioSamples(count) < BIGBUFFSIZE) { |
| 1194 | 1 | samples = new(std::nothrow) short[BIGBUFFSIZE/sizeof(short)]; | |
| 1195 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 11 not taken.
|
1 | if (samples) { |
| 1196 | 1 | bigbuff=true; | |
| 1197 | 1 | bcount = vi.AudioSamplesFromBytes(BIGBUFFSIZE); | |
| 1198 | } | ||
| 1199 | else { | ||
| 1200 | ✗ | samples = (short*)buf; // malloc failed just reuse clients buffer | |
| 1201 | } | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | 1 | const int64_t passes = vi.num_audio_samples / bcount; | |
| 1205 | 1 | int64_t negpeaksampleno=-1, pospeaksampleno=-1; | |
| 1206 | 1 | int i_pos_volume = 0; | |
| 1207 | 1 | int i_neg_volume = 0; | |
| 1208 | 1 | const int chanXbcount = (int)bcount * vi.AudioChannels(); | |
| 1209 | |||
| 1210 |
1/2✗ Branch 26 → 14 not taken.
✓ Branch 26 → 27 taken 1 time.
|
1 | for (int64_t i = 0; i < passes; i++) { |
| 1211 | ✗ | child->GetAudio(samples, bcount*i, bcount, env); | |
| 1212 | ✗ | for (int j = 0; j < chanXbcount; j++) { | |
| 1213 | ✗ | const int sample=samples[j]; | |
| 1214 | ✗ | if (sample < i_neg_volume) { // Cope with MIN_SHORT | |
| 1215 | ✗ | i_neg_volume = sample; | |
| 1216 | ✗ | negpeaksampleno = chanXbcount*i+j; | |
| 1217 | ✗ | if (sample <= -32767) { | |
| 1218 | ✗ | i = passes; | |
| 1219 | ✗ | break; | |
| 1220 | } | ||
| 1221 | } | ||
| 1222 | ✗ | else if (sample > i_pos_volume) { | |
| 1223 | ✗ | i_pos_volume = sample; | |
| 1224 | ✗ | pospeaksampleno = chanXbcount*i+j; | |
| 1225 | ✗ | if (sample == 32767) { | |
| 1226 | ✗ | i = passes; | |
| 1227 | ✗ | break; | |
| 1228 | } | ||
| 1229 | } | ||
| 1230 | } | ||
| 1231 | } | ||
| 1232 | // Remaining samples | ||
| 1233 |
2/4✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 39 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 39 not taken.
|
1 | if ((i_pos_volume != 32767) && (i_neg_volume > -32767)) { |
| 1234 | 1 | const int64_t rem_samples = vi.num_audio_samples % bcount; | |
| 1235 | 1 | const int chanXremcount = (int)rem_samples * vi.AudioChannels(); | |
| 1236 | |||
| 1237 | 1 | child->GetAudio(samples, bcount*passes, rem_samples, env); | |
| 1238 |
2/2✓ Branch 38 → 33 taken 3 times.
✓ Branch 38 → 39 taken 1 time.
|
4 | for (int j = 0; j < chanXremcount; j++) { |
| 1239 | 3 | const int sample=samples[j]; | |
| 1240 |
2/2✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 35 taken 2 times.
|
3 | if (sample < i_neg_volume) { // Cope with MIN_SHORT |
| 1241 | 1 | i_neg_volume = sample; | |
| 1242 | 1 | negpeaksampleno = chanXbcount*passes+j; | |
| 1243 | } | ||
| 1244 |
2/2✓ Branch 35 → 36 taken 1 time.
✓ Branch 35 → 37 taken 1 time.
|
2 | else if (sample > i_pos_volume) { |
| 1245 | 1 | i_pos_volume = sample; | |
| 1246 | 1 | pospeaksampleno = chanXbcount*passes+j; | |
| 1247 | } | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 |
2/4✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 42 not taken.
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 42 not taken.
|
1 | if (bigbuff) delete[] samples; |
| 1251 | |||
| 1252 | 1 | i_pos_volume = -i_pos_volume; // Remember -ve has 1 more range than +ve, i.e. -32768 | |
| 1253 |
1/2✓ Branch 42 → 43 taken 1 time.
✗ Branch 42 → 46 not taken.
|
1 | if (i_neg_volume < i_pos_volume) { |
| 1254 | 1 | i_pos_volume = i_neg_volume; | |
| 1255 | 1 | frameno = vi.FramesFromAudioSamples(negpeaksampleno / vi.AudioChannels()); | |
| 1256 | } | ||
| 1257 | else { | ||
| 1258 | ✗ | frameno = vi.FramesFromAudioSamples(pospeaksampleno / vi.AudioChannels()); | |
| 1259 | } | ||
| 1260 | 1 | max_volume = float(i_pos_volume * (-1.0/32768.0)); | |
| 1261 | 1 | max_factor = max_factor / max_volume; | |
| 1262 | |||
| 1263 |
1/2✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 84 not taken.
|
1 | } else if (vi.SampleType() == SAMPLE_FLOAT) { // Float |
| 1264 | 1 | int64_t bcount = count; | |
| 1265 | 1 | SFLOAT* samples = (SFLOAT*)buf; | |
| 1266 | 1 | bool bigbuff=false; | |
| 1267 | |||
| 1268 |
1/2✓ Branch 53 → 54 taken 1 time.
✗ Branch 53 → 59 not taken.
|
1 | if (vi.BytesFromAudioSamples(count) < BIGBUFFSIZE) { |
| 1269 | 1 | samples = new(std::nothrow) SFLOAT[BIGBUFFSIZE/sizeof(SFLOAT)]; | |
| 1270 |
1/2✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 58 not taken.
|
1 | if (samples) { |
| 1271 | 1 | bigbuff=true; | |
| 1272 | 1 | bcount = vi.AudioSamplesFromBytes(BIGBUFFSIZE); | |
| 1273 | } | ||
| 1274 | else { | ||
| 1275 | ✗ | samples = (SFLOAT*)buf; // malloc failed just reuse clients buffer | |
| 1276 | } | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | 1 | const int chanXbcount = (int)bcount * vi.AudioChannels(); | |
| 1280 | 1 | const int64_t passes = vi.num_audio_samples / bcount; | |
| 1281 | 1 | int64_t peaksampleno=-1; | |
| 1282 | |||
| 1283 |
1/2✗ Branch 69 → 61 not taken.
✓ Branch 69 → 70 taken 1 time.
|
1 | for (int64_t i = 0;i < passes;i++) { |
| 1284 | ✗ | child->GetAudio(samples, bcount*i, bcount, env); | |
| 1285 | ✗ | for (int j = 0;j < chanXbcount;j++) { | |
| 1286 | ✗ | const SFLOAT sample = fabsf(samples[j]); | |
| 1287 | ✗ | if (sample > max_volume) { | |
| 1288 | ✗ | max_volume = sample; | |
| 1289 | ✗ | peaksampleno = chanXbcount*i+j; | |
| 1290 | } | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | // Remaining samples | ||
| 1294 | 1 | const int64_t rem_samples = vi.num_audio_samples % bcount; | |
| 1295 | 1 | const int chanXremcount = (int)rem_samples * vi.AudioChannels(); | |
| 1296 | |||
| 1297 | 1 | child->GetAudio(samples, bcount*passes, rem_samples, env); | |
| 1298 |
2/2✓ Branch 77 → 74 taken 4 times.
✓ Branch 77 → 78 taken 1 time.
|
5 | for (int j = 0;j < chanXremcount;j++) { |
| 1299 | 4 | const SFLOAT sample = fabsf(samples[j]); | |
| 1300 |
2/2✓ Branch 74 → 75 taken 2 times.
✓ Branch 74 → 76 taken 2 times.
|
4 | if (sample > max_volume) { |
| 1301 | 2 | max_volume = sample; | |
| 1302 | 2 | peaksampleno = chanXbcount*passes+j; | |
| 1303 | } | ||
| 1304 | } | ||
| 1305 |
2/4✓ Branch 78 → 79 taken 1 time.
✗ Branch 78 → 81 not taken.
✓ Branch 79 → 80 taken 1 time.
✗ Branch 79 → 81 not taken.
|
1 | if (bigbuff) delete[] samples; |
| 1306 | |||
| 1307 | 1 | frameno = vi.FramesFromAudioSamples(peaksampleno / vi.AudioChannels()); | |
| 1308 | 1 | max_factor = max_factor / max_volume; | |
| 1309 | } | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | 2 | const int chanXcount = (int)count * vi.AudioChannels(); | |
| 1313 | |||
| 1314 |
2/2✓ Branch 86 → 87 taken 1 time.
✓ Branch 86 → 94 taken 1 time.
|
2 | if (vi.SampleType() == SAMPLE_INT16) { |
| 1315 | 1 | const int factor = (int)(max_factor * 131072.0f + 0.5f); | |
| 1316 | 1 | child->GetAudio(buf, start, count, env); | |
| 1317 | |||
| 1318 | #if defined(X86_32) && defined(MSVC) | ||
| 1319 | const short* endsample = (short*)buf + chanXcount; | ||
| 1320 | |||
| 1321 | __asm { | ||
| 1322 | mov ecx, [factor] | ||
| 1323 | mov edi, [buf] | ||
| 1324 | align 16 | ||
| 1325 | iloop2: | ||
| 1326 | movsx eax, WORD PTR [edi] ; *samples | ||
| 1327 | imul ecx | ||
| 1328 | add edi, 2 ; samples++ | ||
| 1329 | add eax, 65536 | ||
| 1330 | adc edx, 0 | ||
| 1331 | |||
| 1332 | cmp edx, -1 ; if (nh < -1) return MIN_SHORT; | ||
| 1333 | jge notnegsat2 | ||
| 1334 | mov eax, -32768 | ||
| 1335 | jmp saturate2 | ||
| 1336 | notnegsat2: | ||
| 1337 | test edx, edx ; if (nh > 0) return MAX_SHORT; | ||
| 1338 | jle notpossat2 | ||
| 1339 | mov eax, 32767 | ||
| 1340 | jmp saturate2 | ||
| 1341 | notpossat2: | ||
| 1342 | shrd eax, edx, 17 ; n>>17 | ||
| 1343 | saturate2: | ||
| 1344 | mov WORD PTR [edi-2], ax ; *samples | ||
| 1345 | |||
| 1346 | cmp edi, [endsample] | ||
| 1347 | jl iloop2 | ||
| 1348 | } | ||
| 1349 | #else | ||
| 1350 | 1 | short* samples = (short*)buf; | |
| 1351 |
2/2✓ Branch 93 → 90 taken 3 times.
✓ Branch 93 → 101 taken 1 time.
|
4 | for (int i = 0; i < chanXcount; ++i) { |
| 1352 | // TODO: This is very slow. Right now, it should just work, we'll optimize later. | ||
| 1353 | 3 | samples[i] = (short)clamp( | |
| 1354 | 3 | signed_saturated_add64(Int32x32To64(samples[i], factor), 65536) >> 17, | |
| 1355 | (int64_t)INT16_MIN, | ||
| 1356 | (int64_t)INT16_MAX); | ||
| 1357 | } | ||
| 1358 | #endif // X86_32 | ||
| 1359 |
1/2✓ Branch 95 → 96 taken 1 time.
✗ Branch 95 → 101 not taken.
|
1 | } else if (vi.SampleType() == SAMPLE_FLOAT) { |
| 1360 | 1 | SFLOAT* samples = (SFLOAT*)buf; | |
| 1361 | 1 | child->GetAudio(buf, start, count, env); | |
| 1362 |
2/2✓ Branch 100 → 99 taken 2 times.
✓ Branch 100 → 101 taken 1 time.
|
3 | for (int i = 0; i < chanXcount; ++i) { |
| 1363 | 2 | samples[i] = samples[i] * max_factor; | |
| 1364 | } | ||
| 1365 | } | ||
| 1366 | 2 | } | |
| 1367 | |||
| 1368 | 1 | int __stdcall Normalize::SetCacheHints(int cachehints, int frame_range) { | |
| 1369 | AVS_UNUSED(frame_range); | ||
| 1370 | |||
| 1371 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
|
1 | switch (cachehints) { |
| 1372 | 1 | case CACHE_GET_MTMODE: | |
| 1373 | 1 | return MT_SERIALIZED; | |
| 1374 | ✗ | default: | |
| 1375 | ✗ | break; | |
| 1376 | } | ||
| 1377 | ✗ | return 0; | |
| 1378 | } | ||
| 1379 | |||
| 1380 | ✗ | PVideoFrame __stdcall Normalize::GetFrame(int n, IScriptEnvironment* env) { | |
| 1381 | ✗ | if (showvalues) { | |
| 1382 | ✗ | PVideoFrame src = child->GetFrame(n, env); | |
| 1383 | ✗ | env->MakeWritable(&src); | |
| 1384 | char text[400]; | ||
| 1385 | |||
| 1386 | ✗ | if (max_volume < 0) { | |
| 1387 | ✗ | sprintf(text, "Normalize: Result not yet calculated!"); | |
| 1388 | } else { | ||
| 1389 | ✗ | double maxdb = 8.685889638 * log(max_factor); | |
| 1390 | // maxdb = (20 * log(factor)) / log(10); | ||
| 1391 | ✗ | sprintf(text, "Amplify Factor: %8.4f\nAmplify DB: %8.4f\nAt Frame: %d", max_factor, maxdb, frameno); | |
| 1392 | } | ||
| 1393 | ✗ | env->ApplyMessage(&src, vi, text, vi.width / 4, 0xf0f080, 0, 0); | |
| 1394 | ✗ | return src; | |
| 1395 | ✗ | } | |
| 1396 | ✗ | return child->GetFrame(n, env); | |
| 1397 | |||
| 1398 | } | ||
| 1399 | |||
| 1400 | |||
| 1401 | ✗ | AVSValue __cdecl Normalize::Create(AVSValue args, void*, IScriptEnvironment*) { | |
| 1402 | |||
| 1403 | ✗ | return new Normalize(args[0].AsClip(), args[1].AsFloatf(1.0f), args[2].AsBool(false));} | |
| 1404 | |||
| 1405 | |||
| 1406 | /***************************** | ||
| 1407 | ***** Mix audio tracks ****** | ||
| 1408 | ******************************/ | ||
| 1409 | |||
| 1410 | 2 | MixAudio::MixAudio(PClip _child, PClip _clip, double _track1_factor, double _track2_factor, IScriptEnvironment* env) : | |
| 1411 |
1/2✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 26 not taken.
|
4 | GenericVideoFilter(ConvertAudio::Create(_child, SAMPLE_INT16 | SAMPLE_FLOAT, SAMPLE_FLOAT)), |
| 1412 | 2 | tempbuffer(NULL), | |
| 1413 | 2 | track1_factor(int(_track1_factor*131072.0 + 0.5)), | |
| 1414 | 2 | track2_factor(int(_track2_factor*131072.0 + 0.5)), | |
| 1415 | 2 | t1factor(float(_track1_factor)), | |
| 1416 |
3/6✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 28 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 24 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 39 not taken.
|
6 | t2factor(float(_track2_factor)) |
| 1417 | { | ||
| 1418 |
5/10✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 35 not taken.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 35 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 34 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 32 not taken.
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 30 not taken.
|
2 | clip = ConvertAudio::Create(_clip, vi.SampleType(), vi.SampleType()); // Clip 2 should now be same type as clip 1. |
| 1419 |
1/2✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 36 not taken.
|
2 | const VideoInfo vi2 = clip->GetVideoInfo(); |
| 1420 | |||
| 1421 |
1/2✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 2 times.
|
2 | if (vi.audio_samples_per_second != vi2.audio_samples_per_second) |
| 1422 | ✗ | env->ThrowError("MixAudio: Clips must have same sample rate! Use ResampleAudio()!"); // Could be removed for fun :) | |
| 1423 | |||
| 1424 |
3/6✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 36 not taken.
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 36 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2 times.
|
2 | if (vi.AudioChannels() != vi2.AudioChannels()) |
| 1425 | ✗ | env->ThrowError("MixAudio: Clips must have same number of channels! Use ConvertToMono() or MergeChannels()!"); | |
| 1426 | |||
| 1427 | 2 | tempbuffer_size = 0; | |
| 1428 | 2 | } | |
| 1429 | |||
| 1430 | |||
| 1431 | 2 | void __stdcall MixAudio::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 1432 |
1/2✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 9 not taken.
|
2 | if (tempbuffer_size < count) |
| 1433 | { | ||
| 1434 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 2 times.
|
2 | if (tempbuffer_size) |
| 1435 | ✗ | delete[] tempbuffer; | |
| 1436 | |||
| 1437 | 2 | tempbuffer = new signed char[(size_t)(count * vi.BytesPerAudioSample())]; | |
| 1438 | 2 | tempbuffer_size = (int)count; | |
| 1439 | } | ||
| 1440 | |||
| 1441 | 2 | child->GetAudio(buf, start, count, env); | |
| 1442 | 2 | clip->GetAudio(tempbuffer, start, count, env); | |
| 1443 | 2 | unsigned channels = vi.AudioChannels(); | |
| 1444 | |||
| 1445 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 22 taken 1 time.
|
2 | if (vi.SampleType()&SAMPLE_INT16) { |
| 1446 | #if defined(X86_32) && defined(MSVC) | ||
| 1447 | const short* tbuffer = (short*)tempbuffer; | ||
| 1448 | const short* endsample = (short*)buf + unsigned(count)*channels; | ||
| 1449 | const int t1_factor = track1_factor; | ||
| 1450 | const int t2_factor = track2_factor; | ||
| 1451 | |||
| 1452 | __asm { | ||
| 1453 | push ebx | ||
| 1454 | mov edi, [buf] | ||
| 1455 | mov esi, [tbuffer] | ||
| 1456 | align 16 | ||
| 1457 | iloop3: | ||
| 1458 | movsx eax, WORD PTR [edi] ; *samples | ||
| 1459 | add edi, 2 ; samples++ | ||
| 1460 | imul [t1_factor] | ||
| 1461 | mov ebx, 65536 | ||
| 1462 | xor ecx, ecx | ||
| 1463 | add ebx, eax | ||
| 1464 | movsx eax, WORD PTR [esi] ; *clip_samples | ||
| 1465 | adc ecx, edx | ||
| 1466 | imul [t2_factor] | ||
| 1467 | add esi, 2 ; clip_samples++ | ||
| 1468 | add eax, ebx | ||
| 1469 | adc edx, ecx | ||
| 1470 | |||
| 1471 | cmp edx, -1 ; if (nh < -1) return MIN_SHORT; | ||
| 1472 | jge notnegsat3 | ||
| 1473 | mov eax, -32768 | ||
| 1474 | jmp saturate3 | ||
| 1475 | notnegsat3: | ||
| 1476 | test edx, edx ; if (nh > 0) return MAX_SHORT; | ||
| 1477 | jle notpossat3 | ||
| 1478 | mov eax, 32767 | ||
| 1479 | jmp saturate3 | ||
| 1480 | notpossat3: | ||
| 1481 | shrd eax, edx, 17 ; n>>17 | ||
| 1482 | saturate3: | ||
| 1483 | mov WORD PTR [edi-2], ax ; *samples | ||
| 1484 | |||
| 1485 | cmp edi, [endsample] | ||
| 1486 | jl iloop3 | ||
| 1487 | pop ebx | ||
| 1488 | } | ||
| 1489 | #else | ||
| 1490 | 1 | short* samples = (short*)buf; | |
| 1491 | 1 | short* clip_samples = (short*)tempbuffer; | |
| 1492 |
2/2✓ Branch 21 → 17 taken 2 times.
✓ Branch 21 → 27 taken 1 time.
|
3 | for (unsigned i = 0; i < unsigned(count)*channels; ++i) { |
| 1493 | 2 | samples[i] = (short)clamp( | |
| 1494 | 2 | signed_saturated_add64(signed_saturated_add64(Int32x32To64(samples[i], track1_factor), Int32x32To64(clip_samples[i], track2_factor)), 65536) >> 17, | |
| 1495 | (int64_t)INT16_MIN, | ||
| 1496 | (int64_t)INT16_MAX); | ||
| 1497 | } | ||
| 1498 | #endif | ||
| 1499 |
1/2✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 27 not taken.
|
1 | } else if (vi.SampleType()&SAMPLE_FLOAT) { |
| 1500 | 1 | SFLOAT* samples = (SFLOAT*)buf; | |
| 1501 | 1 | const SFLOAT* clip_samples = (SFLOAT*)tempbuffer; | |
| 1502 |
2/2✓ Branch 26 → 25 taken 6 times.
✓ Branch 26 → 27 taken 1 time.
|
7 | for (unsigned i = 0; i < unsigned(count)*channels; ++i) { |
| 1503 | 6 | samples[i] = (samples[i] * t1factor) + (clip_samples[i] * t2factor); | |
| 1504 | } | ||
| 1505 | } | ||
| 1506 | 2 | } | |
| 1507 | |||
| 1508 | 1 | int __stdcall MixAudio::SetCacheHints(int cachehints, int frame_range) { | |
| 1509 | AVS_UNUSED(frame_range); | ||
| 1510 | |||
| 1511 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
|
1 | switch (cachehints) { |
| 1512 | 1 | case CACHE_GET_MTMODE: | |
| 1513 | 1 | return MT_SERIALIZED; | |
| 1514 | ✗ | default: | |
| 1515 | ✗ | break; | |
| 1516 | } | ||
| 1517 | ✗ | return 0; | |
| 1518 | } | ||
| 1519 | |||
| 1520 | ✗ | AVSValue __cdecl MixAudio::Create(AVSValue args, void*, IScriptEnvironment* env) { | |
| 1521 | ✗ | double track1_factor = args[2].AsDblDef(0.5); | |
| 1522 | ✗ | double track2_factor = args[3].AsDblDef(1.0 - track1_factor); | |
| 1523 | ✗ | return new MixAudio(args[0].AsClip(), args[1].AsClip(), track1_factor, track2_factor, env); | |
| 1524 | } | ||
| 1525 | |||
| 1526 | |||
| 1527 | |||
| 1528 | /******************************** | ||
| 1529 | ******* Resample Audio ****** | ||
| 1530 | *******************************/ | ||
| 1531 | |||
| 1532 | static int Amasktab[Amask+1]; | ||
| 1533 | static SFLOAT fAmasktab[Amask+1]; | ||
| 1534 | |||
| 1535 | 4 | ResampleAudio::ResampleAudio(PClip _child, int _target_rate_n, int _target_rate_d, IScriptEnvironment*) | |
| 1536 |
1/2✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 36 not taken.
|
8 | : GenericVideoFilter(ConvertAudio::Create(_child, SAMPLE_INT16 | SAMPLE_FLOAT, SAMPLE_FLOAT)), |
| 1537 |
2/4✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 38 not taken.
✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 34 not taken.
|
8 | factor(_target_rate_n / (double(_target_rate_d) * vi.audio_samples_per_second)) |
| 1538 | { | ||
| 1539 | 4 | srcbuffer = 0; | |
| 1540 | 4 | fsrcbuffer = 0; | |
| 1541 | |||
| 1542 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 4 times.
|
4 | if (vi.audio_samples_per_second == 0) { |
| 1543 | ✗ | skip_conversion = true; | |
| 1544 | ✗ | return ; | |
| 1545 | } | ||
| 1546 | |||
| 1547 | // To avoid overflow, implement as (A*B+C/2)/C = (A/C)*B + ((A%C)*B+C>>1)/C | ||
| 1548 | 4 | const int64_t den = Int32x32To64(_target_rate_d, vi.audio_samples_per_second); | |
| 1549 | 4 | const int64_t num_audio_samples = (vi.num_audio_samples/den) * _target_rate_n + ((vi.num_audio_samples%den)*_target_rate_n + (den>>1))/den; | |
| 1550 | |||
| 1551 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 4 times.
|
4 | if (vi.num_audio_samples == num_audio_samples) { |
| 1552 | ✗ | skip_conversion = true; | |
| 1553 | ✗ | return ; | |
| 1554 | } | ||
| 1555 | 4 | skip_conversion = false; | |
| 1556 | 4 | vi.num_audio_samples = num_audio_samples; | |
| 1557 | 4 | vi.audio_samples_per_second = (_target_rate_n + (_target_rate_d>>1))/_target_rate_d; | |
| 1558 | |||
| 1559 |
3/4✓ Branch 11 → 12 taken 4 times.
✗ Branch 11 → 41 not taken.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 23 taken 2 times.
|
4 | if (vi.IsSampleType(SAMPLE_INT16)) { |
| 1560 | 2 | double dLpScl = 0.0; | |
| 1561 | |||
| 1562 | // Load interpolate ratio table | ||
| 1563 |
2/2✓ Branch 15 → 14 taken 256 times.
✓ Branch 15 → 16 taken 2 times.
|
258 | for (int i=0; i<=Amask; i++) |
| 1564 | 256 | Amasktab[i] = (i<<16) | (Amask+1-i); /* a is between 0 and 1 */ | |
| 1565 | |||
| 1566 | // generate filter coefficients | ||
| 1567 |
1/2✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 40 not taken.
|
2 | makeFilter(Imp, dLpScl, Nwing, 0.90, 9); |
| 1568 | 2 | Imp[Nwing] = 0; // for "interpolation" beyond last coefficient | |
| 1569 | |||
| 1570 | /* Account for increased filter gain when using factors less than 1 */ | ||
| 1571 |
1/2✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 2 times.
|
2 | if (factor < 1) |
| 1572 | ✗ | dLpScl = dLpScl * factor; | |
| 1573 | |||
| 1574 | // Attenuate resampler scale factor by 0.95 to reduce probability of clipping | ||
| 1575 | 2 | LpScl = int(dLpScl * 0.95 + 0.5); | |
| 1576 | |||
| 1577 | // Scale guard bits so intermediate result fits in short | ||
| 1578 | 2 | mNhg = Nhg; | |
| 1579 |
2/2✓ Branch 21 → 20 taken 2 times.
✓ Branch 21 → 22 taken 2 times.
|
4 | while (dLpScl < 16384.0) { |
| 1580 | 2 | dLpScl *= 2.0; | |
| 1581 | 2 | mNhg += 1; | |
| 1582 | } | ||
| 1583 | 2 | mLpScl = int(dLpScl + 0.5); // Must be 16384 <= mLpScl <= 32767 | |
| 1584 | } | ||
| 1585 | else { // SAMPLE_FLOAT | ||
| 1586 | |||
| 1587 | // Load interpolate ratio table | ||
| 1588 |
2/2✓ Branch 25 → 24 taken 256 times.
✓ Branch 25 → 26 taken 2 times.
|
258 | for (int i=0; i<=Amask; i++) |
| 1589 | 256 | fAmasktab[i] = float(i) / (Amask+1); /* a is between 0 and 1 */ | |
| 1590 | |||
| 1591 | /* Account for increased filter gain when using factors less than 1 */ | ||
| 1592 |
1/2✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 2 times.
|
2 | if (factor < 1) |
| 1593 | ✗ | makeFilter(fImp, factor, Nwing, 0.90, 9); // generate filter coefficients | |
| 1594 | else | ||
| 1595 | 2 | makeFilter(fImp, 1.0, Nwing, 0.90, 9); // generate filter coefficients | |
| 1596 | |||
| 1597 | 2 | fImp[Nwing] = 0.0; // for "interpolation" beyond last coefficient | |
| 1598 | |||
| 1599 | } | ||
| 1600 | |||
| 1601 | /* Calc reach of LP filter wing & give some creeping room */ | ||
| 1602 | 4 | Xoff = int(((Nmult + 1) / 2.0) * max(1.0, 1.0 / factor)) + 10; | |
| 1603 | |||
| 1604 | /* The previous algorithm was causing quite a noticable click or pop at the | ||
| 1605 | * end of each mouthful due to accumulated creep between pos+N*dtb at the | ||
| 1606 | * end of one call to (start/factor*(1<<Np)+0.5) in the next. | ||
| 1607 | */ | ||
| 1608 | 4 | double dt = (1 << Np) / factor; /* Output sampling period */ | |
| 1609 | 4 | dtb = int(dt); /* Yes! Truncated not rounded */ | |
| 1610 | 4 | dt -= dtb; /* 0 <= SamplingPeriodDeficit < 1 */ | |
| 1611 | 4 | dtbe = unsigned((1 << 31) * dt + 0.5); /* Prevent creep, bump dtb every (2^31)/dtbe samples */ | |
| 1612 | |||
| 1613 | 4 | double dh = min(double(Npc), factor * Npc); /* Filter sampling period */ | |
| 1614 | 4 | dhb = int(dh * (1 << Na) + 0.5); | |
| 1615 | ✗ | } | |
| 1616 | |||
| 1617 | |||
| 1618 | 6 | void __stdcall ResampleAudio::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 1619 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 6 times.
|
6 | if (skip_conversion) { |
| 1620 | ✗ | child->GetAudio(buf, start, count, env); | |
| 1621 | ✗ | return ; | |
| 1622 | } | ||
| 1623 | 6 | auto src_start = int64_t(((long double)start / factor) * (1 << Np) + 0.5); | |
| 1624 | 6 | auto src_end = int64_t(((long double)(start + count) / factor) * (1 << Np) + 0.5); | |
| 1625 | 6 | const int64_t source_samples = ((src_end - src_start) >> Np) + 2 * Xoff + 1; | |
| 1626 | 6 | const int source_bytes = (int)vi.BytesFromAudioSamples(source_samples); | |
| 1627 | |||
| 1628 | 6 | int64_t pos = (int(src_start & Pmask)) + (Xoff << Np); | |
| 1629 | 6 | short ch = (short)vi.AudioChannels(); | |
| 1630 | 6 | unsigned dtberror = 0; | |
| 1631 | |||
| 1632 |
2/2✓ Branch 9 → 10 taken 3 times.
✓ Branch 9 → 42 taken 3 times.
|
6 | if (vi.IsSampleType(SAMPLE_INT16)) { |
| 1633 | |||
| 1634 |
3/4✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 2 times.
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 19 not taken.
|
3 | if (!srcbuffer || source_bytes > srcbuffer_size) { |
| 1635 |
2/2✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 2 times.
|
3 | delete[] srcbuffer; |
| 1636 |
1/2✓ Branch 14 → 15 taken 3 times.
✗ Branch 14 → 16 not taken.
|
3 | srcbuffer = new short[source_bytes >> 1]; |
| 1637 | 3 | srcbuffer_size = source_bytes; | |
| 1638 | 3 | last_samples= 0; | |
| 1639 | 3 | last_start = 0; | |
| 1640 | } | ||
| 1641 | |||
| 1642 | 3 | const int offset = int((src_start >> Np) - Xoff - last_start); // Difference from last time | |
| 1643 | 3 | last_start = (src_start >> Np) - Xoff; // Start for next time | |
| 1644 | |||
| 1645 | 3 | int overlap = int(last_samples - offset); // How many samples already fetched | |
| 1646 |
1/4✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 3 times.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
|
3 | if ((offset < 0) || (overlap <= 0)) // Is there any overlap? |
| 1647 | 3 | overlap = 0; | |
| 1648 | ✗ | else if (offset*ch >= 2) // Assume 32bit separation is okay // Yes, copy to start of buffer | |
| 1649 | ✗ | memcpy(srcbuffer, srcbuffer+offset*ch, overlap*ch<<1); // fast | |
| 1650 | ✗ | else if (offset > 0) | |
| 1651 | ✗ | memmove(srcbuffer, srcbuffer+offset*ch, overlap*ch<<1); // slow | |
| 1652 | |||
| 1653 | 3 | last_samples= max<int64_t>(overlap, source_samples); // Samples for next time | |
| 1654 | |||
| 1655 |
1/2✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 30 not taken.
|
3 | if (source_samples-overlap > 0) // Get the rest of the source samples |
| 1656 | 3 | child->GetAudio(&srcbuffer[overlap*ch], last_start+overlap, source_samples-overlap, env); | |
| 1657 | |||
| 1658 | 3 | short* dst = (short*)buf; | |
| 1659 | |||
| 1660 | 3 | short* dst_end = &dst[count * ch]; | |
| 1661 | |||
| 1662 | #ifdef INTEL_INTRINSICS | ||
| 1663 | #if defined(X86_32) && defined(MSVC_PURE) | ||
| 1664 | if (env->GetCPUFlags() & CPUF_MMX) | ||
| 1665 | { | ||
| 1666 | static const int r_Na = 1 << (Na-1); | ||
| 1667 | static const int r_Nhxn = 1 << (Nhxn-1); | ||
| 1668 | static const int r_NLpScl = 1 << (NLpScl-1); | ||
| 1669 | const int inc = ch * sizeof(short); | ||
| 1670 | int posNp = int(pos >> Np); | ||
| 1671 | |||
| 1672 | // MM7 - Accumulate the left/right wing inner product of the current sample pair | ||
| 1673 | // MM6 - Rounding constant 1 << (Na-1), (64) | ||
| 1674 | // MM5 - Rounding constant 1 << (Nhxn-1), (8192) | ||
| 1675 | // MM4 - Scaled scaling factor, mLpScl | ||
| 1676 | // MM3 - Rounding constant 1 << (NLpScl-1), (4096) | ||
| 1677 | // MM2 - Scaled number of guard bits, mNhg | ||
| 1678 | |||
| 1679 | __asm { | ||
| 1680 | movd mm6, [r_Na] ; 1 << (Na - 1) | ||
| 1681 | movd mm5, [r_Nhxn] ; 1 << (Nhxn - 1) | ||
| 1682 | punpckldq mm6, mm6 ; 00000040 00000040 | ||
| 1683 | mov eax, this | ||
| 1684 | punpckldq mm5, mm5 ; 00002000 00002000 | ||
| 1685 | movd mm4, [eax].mLpScl ; 00000000 LpScl | ||
| 1686 | movd mm3, [r_NLpScl] ; 1 << (NLpScl-1) | ||
| 1687 | punpckldq mm4, mm4 ; LpScl | LpScl | ||
| 1688 | movd mm2, [eax].mNhg ; Number of guard bits | ||
| 1689 | punpckldq mm3, mm3 ; 00001000 00001000 | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | while (dst < dst_end) { | ||
| 1693 | for (int q = 0; q < ch; q+=2) { // do 2 channels at once | ||
| 1694 | bool single = (q+1 >= ch); | ||
| 1695 | short* Xp = &srcbuffer[posNp * ch]; | ||
| 1696 | |||
| 1697 | __asm pxor mm7, mm7; // 2 channel samples are accumulated in MM7 | ||
| 1698 | |||
| 1699 | FilterUD_mmx(Xp + ch + q, (unsigned)(-pos) & Pmask, inc, dhb, Imp, Nwing); /* Perform right-wing inner product */ | ||
| 1700 | FilterUD_mmx(Xp + q, (unsigned)( pos) & Pmask, -inc, dhb, Imp, Nwing); /* Perform left-wing inner product */ | ||
| 1701 | |||
| 1702 | __asm { | ||
| 1703 | psrad mm7, mm2 ; scaled Nhg guard bits | ||
| 1704 | mov eax, [dst] | ||
| 1705 | pmaddwd mm7, mm4 ; Normalize for unity filter gain | ||
| 1706 | test byte ptr[single], 1 ; doing 1 sample or 2 samples? | ||
| 1707 | paddd mm7, mm3 ; round | ||
| 1708 | jnz dosingle | ||
| 1709 | psrad mm7, NLpScl ; strip guard bits | ||
| 1710 | add eax, 4 ; dst+=2 | ||
| 1711 | packssdw mm7, mm7 ; pack with signed saturation ready for output | ||
| 1712 | mov [dst], eax | ||
| 1713 | movd [eax-4], mm7 ; deposit 2 output samples | ||
| 1714 | jmp done1 | ||
| 1715 | align 16 | ||
| 1716 | dosingle: | ||
| 1717 | psrad mm7, NLpScl ; strip guard bits | ||
| 1718 | add eax, 2 ; dst+= | ||
| 1719 | packssdw mm7, mm7 ; pack with signed saturation ready for output | ||
| 1720 | mov [dst], eax | ||
| 1721 | movd edx, mm7 | ||
| 1722 | mov [eax-2], dx ; deposit 1 output sample | ||
| 1723 | align 16 | ||
| 1724 | done1: | ||
| 1725 | } | ||
| 1726 | } // for (int q = 0 | ||
| 1727 | __asm { // Don't be a creep ;-) | ||
| 1728 | mov edx, this | ||
| 1729 | mov eax, dtberror ; time increment error accumulator | ||
| 1730 | mov ecx, [edx].dtb ; time increment | ||
| 1731 | add eax, [edx].dtbe ; add error per cycle | ||
| 1732 | mov edx, dword ptr pos+4 | ||
| 1733 | cmp eax, 0x80000000 ; accumulated 1 full error yet? | ||
| 1734 | jb nofix | ||
| 1735 | inc ecx ; += 1 | ||
| 1736 | sub eax, 0x80000000 ; -= 1 full error | ||
| 1737 | nofix: | ||
| 1738 | add ecx, dword ptr pos ; Move to next sample | ||
| 1739 | mov dtberror, eax | ||
| 1740 | adc edx, 0 | ||
| 1741 | mov dword ptr pos, ecx | ||
| 1742 | shrd ecx, edx, Np ; posNp = pos >> Np | ||
| 1743 | mov dword ptr pos+4, edx | ||
| 1744 | mov posNp, ecx | ||
| 1745 | } | ||
| 1746 | } // while (dst | ||
| 1747 | __asm emms; | ||
| 1748 | } | ||
| 1749 | else | ||
| 1750 | #endif // X86_32 | ||
| 1751 | #endif | ||
| 1752 | { | ||
| 1753 |
2/2✓ Branch 41 → 31 taken 24 times.
✓ Branch 41 → 71 taken 3 times.
|
27 | while (dst < dst_end) { |
| 1754 |
2/2✓ Branch 36 → 32 taken 24 times.
✓ Branch 36 → 37 taken 24 times.
|
48 | for (int q = 0; q < ch; q++) { |
| 1755 | 24 | short* Xp = &srcbuffer[(pos >> Np) * ch]; | |
| 1756 | #if 1 | ||
| 1757 | 24 | int64_t v64 = FilterUD(Xp + q, (short)(pos & Pmask), - ch); /* Perform left-wing inner product */ | |
| 1758 | 24 | v64 += FilterUD(Xp + ch + q, (short)(( -pos) & Pmask), ch); /* Perform right-wing inner product */ | |
| 1759 | 24 | v64 += 1 << (Nh - 1); /* Round only once! */ | |
| 1760 | 24 | int v32 = int(v64 >> Nh); /* Make guard bits once! */ | |
| 1761 | 24 | v32 *= LpScl; /* Normalize for unity filter gain */ | |
| 1762 | 24 | *dst++ = IntToShort(v32, NLpScl); /* strip guard bits, deposit output */ | |
| 1763 | #else | ||
| 1764 | int v = FilterUD(Xp + q, (short)(pos & Pmask), - ch); /* Perform left-wing inner product */ | ||
| 1765 | v += FilterUD(Xp + ch + q, (short)(( -pos) & Pmask), ch); /* Perform right-wing inner product */ | ||
| 1766 | v >>= Nhg; /* Make guard bits */ | ||
| 1767 | v *= LpScl; /* Normalize for unity filter gain */ | ||
| 1768 | *dst++ = IntToShort(v, NLpScl); /* strip guard bits, deposit output */ | ||
| 1769 | #endif | ||
| 1770 | } | ||
| 1771 |
2/2✓ Branch 37 → 38 taken 9 times.
✓ Branch 37 → 39 taken 15 times.
|
24 | if ((dtberror += dtbe) >= (1u << 31)) { // Don't be a creep ;-) |
| 1772 | 9 | dtberror -= (1u << 31); | |
| 1773 | 9 | pos += dtb + 1; /* Move to next sample by time increment + error adjustment */ | |
| 1774 | } | ||
| 1775 | else { | ||
| 1776 | 15 | pos += dtb; /* Move to next sample by time increment */ | |
| 1777 | } | ||
| 1778 | } | ||
| 1779 | } | ||
| 1780 | } | ||
| 1781 | else { // SAMPLE_FLOAT | ||
| 1782 | |||
| 1783 |
3/4✓ Branch 42 → 43 taken 1 time.
✓ Branch 42 → 44 taken 2 times.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 51 not taken.
|
3 | if (!fsrcbuffer || source_bytes > srcbuffer_size) { |
| 1784 |
2/2✓ Branch 44 → 45 taken 1 time.
✓ Branch 44 → 46 taken 2 times.
|
3 | delete[] fsrcbuffer; |
| 1785 |
1/2✓ Branch 46 → 47 taken 3 times.
✗ Branch 46 → 48 not taken.
|
3 | fsrcbuffer = new SFLOAT[source_bytes >> 2]; |
| 1786 | 3 | srcbuffer_size = source_bytes; | |
| 1787 | 3 | last_samples= 0; | |
| 1788 | 3 | last_start = 0; | |
| 1789 | } | ||
| 1790 | |||
| 1791 | 3 | const int offset = int((src_start >> Np) - Xoff - last_start); | |
| 1792 | 3 | last_start = (src_start >> Np) - Xoff; | |
| 1793 | |||
| 1794 | 3 | int overlap = int(last_samples - offset); | |
| 1795 |
1/4✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 3 times.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 54 not taken.
|
3 | if ((offset < 0) || (overlap <= 0)) |
| 1796 | 3 | overlap = 0; | |
| 1797 | ✗ | else if (offset > 0) | |
| 1798 | ✗ | memcpy(fsrcbuffer, fsrcbuffer+offset*ch, overlap*ch<<2); | |
| 1799 | 3 | last_samples= max<int64_t>(overlap, source_samples); | |
| 1800 | |||
| 1801 |
1/2✓ Branch 57 → 58 taken 3 times.
✗ Branch 57 → 60 not taken.
|
3 | if (source_samples-overlap > 0) |
| 1802 | 3 | child->GetAudio(&fsrcbuffer[overlap*ch], last_start+overlap, source_samples-overlap, env); | |
| 1803 | |||
| 1804 | 3 | SFLOAT* dst = (SFLOAT*)buf; | |
| 1805 | |||
| 1806 | 3 | SFLOAT* dst_end = &dst[count * ch]; | |
| 1807 | |||
| 1808 |
2/2✓ Branch 70 → 61 taken 24 times.
✓ Branch 70 → 71 taken 3 times.
|
27 | while (dst < dst_end) { |
| 1809 |
2/2✓ Branch 65 → 62 taken 24 times.
✓ Branch 65 → 66 taken 24 times.
|
48 | for (int q = 0; q < ch; q++) { |
| 1810 | 24 | SFLOAT* Xp = &fsrcbuffer[(pos >> Np) * ch]; | |
| 1811 | 24 | SFLOAT v = FilterUD(Xp + q, (short)( pos & Pmask), - ch); /* Perform left-wing inner product */ | |
| 1812 | 24 | v += FilterUD(Xp + ch + q, (short)(( -pos) & Pmask), ch); /* Perform right-wing inner product */ | |
| 1813 | 24 | *dst++ = v; /* deposit output */ | |
| 1814 | } | ||
| 1815 |
2/2✓ Branch 66 → 67 taken 9 times.
✓ Branch 66 → 68 taken 15 times.
|
24 | if ((dtberror += dtbe) >= (1 << 31)) { // Don't be a creep ;-) |
| 1816 | 9 | dtberror -= (1u << 31); | |
| 1817 | 9 | pos += dtb + 1; /* Move to next sample by time increment + error adjustment */ | |
| 1818 | } | ||
| 1819 | else { | ||
| 1820 | 15 | pos += dtb; /* Move to next sample by time increment */ | |
| 1821 | } | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | } | ||
| 1825 | } | ||
| 1826 | |||
| 1827 | 2 | int __stdcall ResampleAudio::SetCacheHints(int cachehints, int frame_range) { | |
| 1828 | AVS_UNUSED(frame_range); | ||
| 1829 | |||
| 1830 |
1/2✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
|
2 | switch (cachehints) { |
| 1831 | 2 | case CACHE_GET_MTMODE: | |
| 1832 | 2 | return MT_SERIALIZED; | |
| 1833 | ✗ | default: | |
| 1834 | ✗ | break; | |
| 1835 | } | ||
| 1836 | ✗ | return 0; | |
| 1837 | } | ||
| 1838 | |||
| 1839 | ✗ | AVSValue __cdecl ResampleAudio::Create(AVSValue args, void*, IScriptEnvironment* env) { | |
| 1840 | ✗ | return new ResampleAudio(args[0].AsClip(), args[1].AsInt(), args[2].AsInt(1), env); | |
| 1841 | } | ||
| 1842 | |||
| 1843 | |||
| 1844 | #ifdef INTEL_INTRINSICS | ||
| 1845 | #if defined(X86_32) && defined(MSVC_PURE) | ||
| 1846 | |||
| 1847 | // FilterUD MMX SAMPLE_INT16 Version -- approx 3.25 times faster than original (2.4x than new) | ||
| 1848 | /* | ||
| 1849 | * MMx registers transfered across calls | ||
| 1850 | * MM7 - Accumulate the left/right wing inner product of the current sample pair | ||
| 1851 | * MM6 - Rounding constant 1 << (Na-1), (64) | ||
| 1852 | * MM5 - Rounding constant 1 << (Nhxn-1), (8192) | ||
| 1853 | * | ||
| 1854 | * Uses MM0, MM1 | ||
| 1855 | */ | ||
| 1856 | #pragma warning( push ) | ||
| 1857 | #pragma warning (disable: 4799) //function '...' has no EMMS instruction | ||
| 1858 | |||
| 1859 | void FilterUD_mmx(short *Xp, unsigned Ph, int _inc, int _dhb, short *p_Imp, unsigned End) { | ||
| 1860 | |||
| 1861 | unsigned Ho = (Ph * (unsigned)_dhb) >> Np; | ||
| 1862 | |||
| 1863 | if (_inc > 0) { // If doing right wing drop extra coeff, so when Ph is | ||
| 1864 | End--; // 0.5, we don't do one too many mult's | ||
| 1865 | if (Ph == 0) // If the phase is zero then we've already skipped the | ||
| 1866 | Ho += _dhb; // first sample, so we must also skip ahead in Imp[] | ||
| 1867 | } | ||
| 1868 | __asm { | ||
| 1869 | mov edi,[Xp] | ||
| 1870 | mov esi,[Ho] | ||
| 1871 | mov ecx,[p_Imp] | ||
| 1872 | |||
| 1873 | mov edx,esi ; Fold into end for improved pairing | ||
| 1874 | mov eax,Amask | ||
| 1875 | shr edx,Na ; Ho >> Na | ||
| 1876 | and eax,esi ; Ho & Amask | ||
| 1877 | cmp edx,[End] | ||
| 1878 | movd mm1,Amasktab[eax*4] ; 0000 0000 eax 128-eax | ||
| 1879 | jae donone | ||
| 1880 | |||
| 1881 | align 16 | ||
| 1882 | loop1: | ||
| 1883 | movd mm0,[ecx+edx*2] ; 0000 0000 Imp[Ho>>Na7+1] Imp[Ho>>Na7] | ||
| 1884 | add esi,[_dhb] ; Ho += dhb | ||
| 1885 | pmaddwd mm0,mm1 ; 00000000 Imp[h+1]*a + Imp[h]*(128-a) | ||
| 1886 | movd mm1,[edi] ; 0000 0000 *(Xp+1) *Xp | ||
| 1887 | paddd mm0,mm6 ; += round | ||
| 1888 | add edi,[_inc] ; Xp += Inc | ||
| 1889 | pslld mm0,16-Na ; <<= 16-Na | ||
| 1890 | mov eax,Amask | ||
| 1891 | psrld mm0,16 ; 0000 0000 0000 coeff | ||
| 1892 | punpcklwd mm1,mm1 ; *(Xp+1) *(Xp+1) *Xp *Xp | ||
| 1893 | mov edx,esi | ||
| 1894 | punpckldq mm0,mm0 ; 0000 coeff 0000 coeff | ||
| 1895 | and eax,esi ; Ho & Amask | ||
| 1896 | pmaddwd mm0,mm1 ; *(Xp+1)*coeff | *Xp*coeff | ||
| 1897 | shr edx,Na ; Ho >> Na | ||
| 1898 | paddd mm0,mm5 ; += round | ||
| 1899 | movd mm1,Amasktab[eax*4] ; 0000 0000 eax 128-eax | ||
| 1900 | psrad mm0,Nhxn ; >>=Nhxn | ||
| 1901 | cmp edx,[End] | ||
| 1902 | paddd mm7,mm0 ; v += t | ||
| 1903 | jb loop1 | ||
| 1904 | donone: | ||
| 1905 | } | ||
| 1906 | } | ||
| 1907 | #pragma warning( pop ) | ||
| 1908 | #endif // X86_32 | ||
| 1909 | #endif | ||
| 1910 | |||
| 1911 | |||
| 1912 | // FilterUD SAMPLE_INT16 Version | ||
| 1913 | 48 | int64_t ResampleAudio::FilterUD(short *Xp, short Ph, short Inc) { | |
| 1914 | 48 | int64_t v = 0; | |
| 1915 | 48 | unsigned Ho = (Ph * (unsigned)dhb) >> Np; | |
| 1916 | 48 | unsigned End = Nwing; | |
| 1917 | |||
| 1918 |
2/2✓ Branch 2 → 3 taken 24 times.
✓ Branch 2 → 5 taken 24 times.
|
48 | if (Inc > 0) /* If doing right wing... */ |
| 1919 | { /* ...drop extra coeff, so when Ph is */ | ||
| 1920 | 24 | End--; /* 0.5, we don't do too many mult's */ | |
| 1921 |
2/2✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 18 times.
|
24 | if (Ph == 0) /* If the phase is zero... */ |
| 1922 | 6 | Ho += dhb; /* ...then we've already skipped the */ | |
| 1923 | } /* first sample, so we must also */ | ||
| 1924 | /* skip ahead in Imp[] and ImpD[] */ | ||
| 1925 |
2/2✓ Branch 7 → 6 taken 1528 times.
✓ Branch 7 → 8 taken 48 times.
|
1576 | while ((Ho >> Na) < End) { |
| 1926 | 1528 | int t = Imp[Ho >> Na]; /* Get IR sample */ | |
| 1927 | #if 1 | ||
| 1928 | // It's 37% faster and more accurate to accumulate 64 bits | ||
| 1929 | // than stuffing around testing, rounding and shifting | ||
| 1930 | 1528 | const int a = Ho & Amask; /* a is logically between 0 and 1 */ | |
| 1931 | 1528 | const int r = 1 << (Na-1); /* Round */ | |
| 1932 | 1528 | t += ((int(Imp[(Ho>>Na)+1]) - t) * a + r) >> Na; /* t is now interp'd filter coeff */ | |
| 1933 | 1528 | t *= *Xp; /* Mult coeff by input sample */ | |
| 1934 | #else | ||
| 1935 | int a = Ho & Amask; /* a is logically between 0 and 1 */ | ||
| 1936 | t += ((int(Imp[(Ho >> Na) + 1]) - t) * a) >> Na; /* t is now interp'd filter coeff */ | ||
| 1937 | t *= *Xp; /* Mult coeff by input sample */ | ||
| 1938 | if (t & 1 << (Nhxn - 1)) /* Round, if needed */ | ||
| 1939 | t += 1 << (Nhxn - 1); | ||
| 1940 | t >>= Nhxn; /* Leave some guard bits, but come back some */ | ||
| 1941 | #endif | ||
| 1942 | 1528 | v += t; /* The filter output */ | |
| 1943 | 1528 | Ho += dhb; /* IR step */ | |
| 1944 | 1528 | Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ | |
| 1945 | } | ||
| 1946 | 48 | return (v); | |
| 1947 | } | ||
| 1948 | |||
| 1949 | // FilterUD SAMPLE_FLOAT Version -- Approx same speed as new int16 and SSRC on P4 (40% on P2) | ||
| 1950 | 48 | SFLOAT ResampleAudio::FilterUD(SFLOAT *Xp, short Ph, short Inc) { | |
| 1951 | 48 | SFLOAT v = 0; | |
| 1952 | 48 | unsigned Ho = (Ph * (unsigned)dhb) >> Np; | |
| 1953 | 48 | unsigned End = Nwing; | |
| 1954 |
2/2✓ Branch 2 → 3 taken 24 times.
✓ Branch 2 → 5 taken 24 times.
|
48 | if (Inc > 0) /* If doing right wing... */ |
| 1955 | { /* ...drop extra coeff, so when Ph is */ | ||
| 1956 | 24 | End--; /* 0.5, we don't do too many mult's */ | |
| 1957 |
2/2✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 18 times.
|
24 | if (Ph == 0) /* If the phase is zero... */ |
| 1958 | 6 | Ho += dhb; /* ...then we've already skipped the */ | |
| 1959 | } /* first sample, so we must also */ | ||
| 1960 | /* skip ahead in fImp[] */ | ||
| 1961 |
2/2✓ Branch 7 → 6 taken 1528 times.
✓ Branch 7 → 8 taken 48 times.
|
1576 | while ((Ho >> Na) < End) { |
| 1962 | 1528 | SFLOAT t = fImp[Ho >> Na]; /* Get IR sample */ | |
| 1963 | 1528 | t += (fImp[(Ho >> Na) + 1] - t) * fAmasktab[Ho & Amask]; /* t is now interpolated filter coeff */ | |
| 1964 | 1528 | t *= *Xp; /* Mult coeff by input sample */ | |
| 1965 | 1528 | v += t; /* The filter output */ | |
| 1966 | 1528 | Ho += dhb; /* IR step */ | |
| 1967 | 1528 | Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ | |
| 1968 | } | ||
| 1969 | 48 | return (v); | |
| 1970 | } | ||
| 1971 | |||
| 1972 | |||
| 1973 | |||
| 1974 | |||
| 1975 | /******************************** | ||
| 1976 | ******* Helper methods ******* | ||
| 1977 | ********************************/ | ||
| 1978 | |||
| 1979 | 32768 | double Izero(double x) { | |
| 1980 | double sum, u, halfx, temp; | ||
| 1981 | int n; | ||
| 1982 | |||
| 1983 | 32768 | sum = u = n = 1; | |
| 1984 | 32768 | halfx = x / 2.0; | |
| 1985 | do { | ||
| 1986 | 746972 | temp = halfx / (double)n; | |
| 1987 | 746972 | n += 1; | |
| 1988 | 746972 | temp *= temp; | |
| 1989 | 746972 | u *= temp; | |
| 1990 | 746972 | sum += u; | |
| 1991 |
2/2✓ Branch 3 → 4 taken 714204 times.
✓ Branch 3 → 5 taken 32768 times.
|
746972 | } while (u >= IzeroEPSILON*sum); |
| 1992 | 32768 | return (sum); | |
| 1993 | } | ||
| 1994 | |||
| 1995 | |||
| 1996 | 4 | void LpFilter(double c[], int N, double frq, double Beta, int Num) { | |
| 1997 | int i; | ||
| 1998 | |||
| 1999 | /* Calculate ideal lowpass filter impulse response coefficients: */ | ||
| 2000 | 4 | c[0] = 2.0 * frq; | |
| 2001 | 4 | const double PIdivNum = PI / Num; | |
| 2002 |
2/2✓ Branch 4 → 3 taken 32764 times.
✓ Branch 4 → 5 taken 4 times.
|
32768 | for (i = 1; i < N; i++) { |
| 2003 | 32764 | const double temp = PIdivNum * i; | |
| 2004 | 32764 | c[i] = sin(2.0 * temp * frq) / temp; /* Analog sinc function, cutoff = frq */ | |
| 2005 | } | ||
| 2006 | |||
| 2007 | /* | ||
| 2008 | * Calculate and Apply Kaiser window to ideal lowpass filter. | ||
| 2009 | * Note: last window value is IBeta which is NOT zero. | ||
| 2010 | * You're supposed to really truncate the window here, not ramp | ||
| 2011 | * it to zero. This helps reduce the first sidelobe. | ||
| 2012 | */ | ||
| 2013 | 4 | const double IBeta = 1.0 / Izero(Beta); | |
| 2014 | 4 | const double inm1 = 1.0 / (N - 1); | |
| 2015 |
2/2✓ Branch 9 → 7 taken 32764 times.
✓ Branch 9 → 10 taken 4 times.
|
32768 | for (i = 1; i < N; i++) { |
| 2016 | 32764 | const double temp = i * inm1; | |
| 2017 | 32764 | c[i] *= Izero(Beta * sqrt(1.0 - temp * temp)) * IBeta; | |
| 2018 | } | ||
| 2019 | 4 | } | |
| 2020 | |||
| 2021 | |||
| 2022 | /* ERROR return codes: | ||
| 2023 | * 0 - no error | ||
| 2024 | * 1 - Nwing too large (Nwing is > MAXNWING) | ||
| 2025 | * 2 - Froll is not in interval [0:1) | ||
| 2026 | * 3 - Beta is < 1.0 | ||
| 2027 | * | ||
| 2028 | */ | ||
| 2029 | |||
| 2030 | // makeFilter SAMPLE_INT16 Version | ||
| 2031 | 2 | int makeFilter( short Imp[], double &dLpScl, unsigned short Nwing, double Froll, double Beta) { | |
| 2032 | static const int MAXNWING = 8192; | ||
| 2033 | static double ImpR[MAXNWING]; | ||
| 2034 | |||
| 2035 | double DCgain, Scl, Maxh; | ||
| 2036 | short Dh; | ||
| 2037 | int i; | ||
| 2038 | |||
| 2039 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
|
2 | if (Nwing > MAXNWING) /* Check for valid parameters */ |
| 2040 | ✗ | return (1); | |
| 2041 |
2/4✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
|
2 | if ((Froll <= 0) || (Froll > 1)) |
| 2042 | ✗ | return (2); | |
| 2043 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2 times.
|
2 | if (Beta < 1) |
| 2044 | ✗ | return (3); | |
| 2045 | |||
| 2046 | /* | ||
| 2047 | * Design Kaiser-windowed sinc-function low-pass filter | ||
| 2048 | */ | ||
| 2049 | 2 | LpFilter(ImpR, (int)Nwing, 0.5*Froll, Beta, Npc); | |
| 2050 | |||
| 2051 | /* Compute the DC gain of the lowpass filter, and its maximum coefficient | ||
| 2052 | * magnitude. Scale the coefficients so that the maximum coeffiecient just | ||
| 2053 | * fits in Nh-bit fixed-point, and compute LpScl as the NLpScl-bit (signed) | ||
| 2054 | * scale factor which when multiplied by the output of the lowpass filter | ||
| 2055 | * gives unity gain. */ | ||
| 2056 | 2 | DCgain = 0; | |
| 2057 | 2 | Dh = Npc; /* Filter sampling period for factors>=1 */ | |
| 2058 |
2/2✓ Branch 12 → 11 taken 62 times.
✓ Branch 12 → 13 taken 2 times.
|
64 | for (i = Dh; i < Nwing; i += Dh) |
| 2059 | 62 | DCgain += ImpR[i]; | |
| 2060 | 2 | DCgain = 2 * DCgain + ImpR[0]; /* DC gain of real coefficients */ | |
| 2061 | |||
| 2062 |
2/2✓ Branch 16 → 14 taken 16384 times.
✓ Branch 16 → 17 taken 2 times.
|
16386 | for (Maxh = i = 0; i < Nwing; i++) |
| 2063 | 16384 | Maxh = max(Maxh, fabs(ImpR[i])); | |
| 2064 | |||
| 2065 | 2 | Scl = ((1 << (Nh - 1)) - 1) / Maxh; /* Map largest coeff to 16-bit maximum */ | |
| 2066 | 2 | dLpScl = fabs((1 << (NLpScl + Nh)) / (DCgain * Scl)); | |
| 2067 | |||
| 2068 | /* Scale filter coefficients for Nh bits and convert to integer */ | ||
| 2069 |
1/2✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 2 times.
|
2 | if (ImpR[0] < 0) /* Need pos 1st value for LpScl storage */ |
| 2070 | ✗ | Scl = -Scl; | |
| 2071 |
2/2✓ Branch 21 → 20 taken 16384 times.
✓ Branch 21 → 22 taken 2 times.
|
16386 | for (i = 0; i < Nwing; i++) /* Scale & round them */ |
| 2072 | 16384 | Imp[i] = short(ImpR[i] * Scl + 0.5); | |
| 2073 | |||
| 2074 | 2 | return (0); | |
| 2075 | } | ||
| 2076 | |||
| 2077 | |||
| 2078 | // makeFilter SAMPLE_FLOAT Version | ||
| 2079 | 2 | int makeFilter( SFLOAT fImp[], double dLpScl, unsigned short Nwing, double Froll, double Beta) { | |
| 2080 | static const int MAXNWING = 8192; | ||
| 2081 | static double ImpR[MAXNWING]; | ||
| 2082 | |||
| 2083 | double DCgain, Scl; | ||
| 2084 | int i; | ||
| 2085 | |||
| 2086 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
|
2 | if (Nwing > MAXNWING) /* Check for valid parameters */ |
| 2087 | ✗ | return (1); | |
| 2088 |
2/4✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
|
2 | if ((Froll <= 0) || (Froll > 1)) |
| 2089 | ✗ | return (2); | |
| 2090 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2 times.
|
2 | if (Beta < 1) |
| 2091 | ✗ | return (3); | |
| 2092 | |||
| 2093 | /* | ||
| 2094 | * Design Kaiser-windowed sinc-function low-pass filter | ||
| 2095 | */ | ||
| 2096 | 2 | LpFilter(ImpR, (int)Nwing, 0.5*Froll, Beta, Npc); | |
| 2097 | |||
| 2098 | /* Compute the DC gain of the lowpass filter, and its maximum coefficient | ||
| 2099 | * magnitude. Scale the coefficients so that the maximum coeffiecient just | ||
| 2100 | * fits in Nh-bit fixed-point, and compute LpScl as the NLpScl-bit (signed) | ||
| 2101 | * scale factor which when multiplied by the output of the lowpass filter | ||
| 2102 | * gives unity gain. */ | ||
| 2103 | 2 | DCgain = 0; | |
| 2104 | /* Npc is filter sampling period for factors>=1 */ | ||
| 2105 |
2/2✓ Branch 12 → 11 taken 62 times.
✓ Branch 12 → 13 taken 2 times.
|
64 | for (i = Npc; i < Nwing; i += Npc) |
| 2106 | 62 | DCgain += ImpR[i]; | |
| 2107 | 2 | DCgain = 2 * DCgain + ImpR[0]; /* DC gain of real coefficients */ | |
| 2108 | |||
| 2109 | 2 | Scl = dLpScl / DCgain; | |
| 2110 | |||
| 2111 | /* Scale filter coefficients for unity gain and convert to float */ | ||
| 2112 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2 times.
|
2 | if (ImpR[0] < 0) /* Need pos 1st value for LpScl storage */ |
| 2113 | ✗ | Scl = -Scl; | |
| 2114 |
2/2✓ Branch 17 → 16 taken 16384 times.
✓ Branch 17 → 18 taken 2 times.
|
16386 | for (i = 0; i < Nwing; i++) /* Scale them */ |
| 2115 | 16384 | fImp[i] = (SFLOAT)(ImpR[i] * Scl); | |
| 2116 | |||
| 2117 | 2 | return (0); | |
| 2118 | } | ||
| 2119 |