GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 60.7% 535 / 0 / 881
Functions: 55.6% 40 / 0 / 72
Branches: 24.0% 284 / 0 / 1182

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