1 /* 2 * Copyright (c) 2009, The MilkyTracker Team. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * - Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * - Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * - Neither the name of the <ORGANIZATION> nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * ResamplerSinc.h 32 * MilkyPlay 33 * 34 * Created by Peter Barth on 03.01.08. 35 * 36 */ 37 38 #include <math.h> 39 40 /* 41 * Sinc resamplers based on: 42 * http://www.cs.princeton.edu/courses/archive/spr07/cos325/src/TimeStuf/srconvrt.c 43 * 44 */ 45 46 #ifndef M_PI 47 #define M_PI 3.14159265358979323846 48 #endif 49 50 #define fpmul MP_FP_MUL 51 52 #define advancePos(CHNsmppos, CHNflags, CHNloopstart, CHNloopend, CHNloopendcopy) \ 53 if (((((CHNflags&3) == 0 || (CHNflags&3) == 1)) && !(CHNflags&ChannelMixer::MP_SAMPLE_BACKWARD)) || \ 54 ((CHNflags&3) == 2 && (CHNflags&ChannelMixer::MP_SAMPLE_BACKWARD) == 0)) \ 55 { \ 56 CHNsmppos++; \ 57 /* stop playing if necessary */ \ 58 if (CHNsmppos>=CHNloopend) \ 59 { \ 60 if ((CHNflags & 3) == 0) \ 61 { \ 62 if (CHNflags & ChannelMixer::MP_SAMPLE_ONESHOT) \ 63 { \ 64 CHNflags &= ~ChannelMixer::MP_SAMPLE_ONESHOT; \ 65 CHNflags |= 1; \ 66 CHNloopend = CHNloopendcopy; \ 67 CHNsmppos = CHNloopstart; \ 68 } \ 69 else \ 70 { \ 71 CHNflags&=~ChannelMixer::MP_SAMPLE_PLAY; \ 72 } \ 73 } \ 74 else if ((CHNflags & 3) == 1) \ 75 { \ 76 CHNsmppos = CHNloopstart; \ 77 } \ 78 else \ 79 { \ 80 CHNflags|=ChannelMixer::MP_SAMPLE_BACKWARD; \ 81 CHNsmppos = CHNloopend-1; \ 82 } \ 83 }\ 84 } \ 85 /* bi-dir loop */ \ 86 else \ 87 { \ 88 CHNsmppos--; \ 89 if (CHNloopstart>CHNsmppos) \ 90 { \ 91 if ((CHNflags & 3) == 0) \ 92 { \ 93 CHNflags&=~ChannelMixer::MP_SAMPLE_PLAY; \ 94 } \ 95 else if ((CHNflags & 3) == 1) \ 96 { \ 97 CHNsmppos = CHNloopend-1; \ 98 } \ 99 else \ 100 { \ 101 CHNflags&=~ChannelMixer::MP_SAMPLE_BACKWARD; \ 102 CHNsmppos = CHNloopstart; \ 103 } \ 104 } \ 105 } 106 107 // double precision sinc without window function 108 109 template<bool ramping, mp_sint32 windowSize, class bufferType, mp_uint32 shift> 110 class SincResamplerDummy 111 { 112 private: sinc(double x)113 static inline double sinc(double x) 114 { 115 if (x==0.0) 116 return 1.0; 117 else 118 { 119 double temp = M_PI * x; 120 return sin(temp) / (temp); 121 } 122 } 123 124 enum 125 { 126 WINDOWSIZE = windowSize, // must be even 127 WIDTH = (WINDOWSIZE / 2) 128 }; 129 130 public: addBlock(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)131 static inline void addBlock(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 132 { 133 const bufferType* sample = (const bufferType*)chn->sample; 134 135 mp_sint32 voll = chn->finalvoll; 136 mp_sint32 volr = chn->finalvolr; 137 138 const mp_sint32 rampFromVolStepL = ramping ? chn->rampFromVolStepL : 0; 139 const mp_sint32 rampFromVolStepR = ramping ? chn->rampFromVolStepR : 0; 140 141 mp_sint32 smppos = chn->smppos; 142 mp_sint32 smpposfrac = chn->smpposfrac; 143 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 144 145 const mp_sint32 flags = chn->flags; 146 const mp_sint32 loopstart = chn->loopstart; 147 const mp_sint32 loopend = chn->loopend; 148 const mp_sint32 loopendcopy = chn->loopendcopy; 149 const mp_sint32 smplen = chn->smplen; 150 151 mp_sint32 fixedtimefrac = chn->fixedtimefrac; 152 const mp_sint32 timeadd = chn->smpadd; 153 154 ChannelMixer::TMixerChannel pos(true); 155 156 while (count--) 157 { 158 double result = 0; 159 160 const double time_now = fixedtimefrac * (1.0 / 65536.0); 161 162 if (abs(smpadd)<65536) 163 { 164 pos.smppos = smppos; 165 pos.loopstart = loopstart; 166 pos.loopend = loopend; 167 pos.loopendcopy = loopendcopy; 168 pos.flags = smpadd < 0 ? (flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) : ((flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) | ChannelMixer::MP_SAMPLE_BACKWARD); 169 // check whether we are outside loop points 170 // if that's the case we're treating the sample as a normal finite signal 171 // note that this is still not totally correct treatment 172 const bool outSideLoop = !(((flags & 3) && pos.smppos >= loopstart && pos.smppos < loopend)); 173 if (outSideLoop) 174 { 175 pos.loopstart = 0; 176 pos.loopend = smplen; 177 pos.flags &= ~3; 178 } 179 180 double time = time_now; 181 if (!fixedtimefrac && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 182 time = 1.0; 183 184 mp_sint32 j; 185 for (j = 0; j<WIDTH; j++) 186 { 187 //double w = 0.42 - 0.5 * cos(2.0*M_PI*(WIDTH-1-j)/(WIDTH*2)) + 0.08*cos(4.0*M_PI*(WIDTH-1-j)/(WIDTH*2)); 188 189 result += (sample[pos.smppos]) * sinc(time); 190 191 time++; 192 advancePos(pos.smppos, pos.flags, pos.loopstart, pos.loopend, pos.loopendcopy); 193 if (!(pos.flags & ChannelMixer::MP_SAMPLE_PLAY)) 194 break; 195 } 196 197 pos.smppos = smppos; 198 pos.flags = smpadd > 0 ? (flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) : ((flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) | ChannelMixer::MP_SAMPLE_BACKWARD); 199 if (outSideLoop) 200 pos.flags &= ~3; 201 202 time = time_now; 203 if (!fixedtimefrac && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 204 time = 1.0; 205 206 for (j = 1; j<WIDTH; j++) 207 { 208 //double w = 0.42 - 0.5 * cos(2.0*M_PI*(j-1+WIDTH)/(WIDTH*2)) + 0.08*cos(4.0*M_PI*(j-1+WIDTH)/(WIDTH*2)); 209 210 advancePos(pos.smppos, pos.flags, pos.loopstart, pos.loopend, pos.loopendcopy); 211 time--; 212 if (!(pos.flags & ChannelMixer::MP_SAMPLE_PLAY)) 213 break; 214 215 result += (sample[pos.smppos]) * sinc(time); 216 } 217 } 218 else 219 { 220 double factor = smpadd * (1.0 / 65536.0); 221 double one_over_factor = 1.0 / factor; 222 223 pos.smppos = smppos; 224 pos.loopstart = loopstart; 225 pos.loopend = loopend; 226 pos.loopendcopy = loopendcopy; 227 pos.flags = smpadd < 0 ? (flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) : ((flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) | ChannelMixer::MP_SAMPLE_BACKWARD); 228 // check whether we are outside loop points 229 // if that's the case we're treating the sample as a normal finite signal 230 // note that this is still not totally correct treatment 231 const bool outSideLoop = !(((flags & 3) && pos.smppos >= loopstart && pos.smppos < loopend)); 232 if (outSideLoop) 233 { 234 pos.loopstart = 0; 235 pos.loopend = smplen; 236 pos.flags &= ~3; 237 } 238 239 double time = time_now; 240 if (!fixedtimefrac && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 241 time = 1.0; 242 243 mp_sint32 j; 244 for (j = 0; j<WIDTH; j++) 245 { 246 //double w = 0.42 - 0.5 * cos(2.0*M_PI*(WIDTH-1-j)/(WIDTH*2)) + 0.08*cos(4.0*M_PI*(WIDTH-1-j)/(WIDTH*2)); 247 248 result += (sample[pos.smppos]) * one_over_factor * sinc(one_over_factor * time); 249 250 advancePos(pos.smppos, pos.flags, pos.loopstart, pos.loopend, pos.loopendcopy); 251 time++; 252 if (!(pos.flags & ChannelMixer::MP_SAMPLE_PLAY)) 253 break; 254 } 255 256 pos.smppos = smppos; 257 pos.flags = smpadd > 0 ? (flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) : ((flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) | ChannelMixer::MP_SAMPLE_BACKWARD); 258 if (outSideLoop) 259 pos.flags &= ~3; 260 261 time = time_now; 262 if (!fixedtimefrac && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 263 time = 1.0; 264 265 for (j = 1; j<WIDTH; j++) 266 { 267 //double w = 0.42 - 0.5 * cos(2.0*M_PI*(j-1+WIDTH)/(WIDTH*2)) + 0.08*cos(4.0*M_PI*(j-1+WIDTH)/(WIDTH*2)); 268 269 advancePos(pos.smppos, pos.flags, pos.loopstart, pos.loopend, pos.loopendcopy); 270 time--; 271 if (!(pos.flags & ChannelMixer::MP_SAMPLE_PLAY)) 272 break; 273 274 result += (sample[pos.smppos]) * one_over_factor * sinc(one_over_factor * time); 275 } 276 } 277 278 279 mp_sint32 final = (mp_sint32)(result*(1 << (16-shift))); 280 281 (*buffer++)+=((final*(voll>>15))>>15); 282 (*buffer++)+=((final*(volr>>15))>>15); 283 284 if (ramping) 285 { 286 voll+=rampFromVolStepL; 287 volr+=rampFromVolStepR; 288 } 289 290 MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16); 291 fixedtimefrac=(fixedtimefrac+timeadd) & 65535; 292 } 293 294 chn->smppos = smppos; 295 chn->smpposfrac = smpposfrac; 296 297 chn->fixedtimefrac = fixedtimefrac; 298 299 if (ramping) 300 { 301 chn->finalvoll = voll; 302 chn->finalvolr = volr; 303 } 304 } 305 306 }; 307 308 template<bool ramping, mp_sint32 windowSize> 309 class ResamplerSinc : public ChannelMixer::ResamplerBase 310 { 311 private: 312 313 public: isRamping()314 virtual bool isRamping() { return ramping; } supportsFullChecking()315 virtual bool supportsFullChecking() { return false; } supportsNoChecking()316 virtual bool supportsNoChecking() { return true; } 317 addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)318 virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 319 { 320 if (chn->flags & 4) 321 SincResamplerDummy<ramping, windowSize, mp_sword, 16>::addBlock(buffer, chn, count); 322 else 323 SincResamplerDummy<ramping, windowSize, mp_sbyte, 8>::addBlock(buffer, chn, count); 324 } 325 }; 326 327 // fixed point sinc with almost hamming window 328 329 // you like that, eh? 330 #define SINCTAB ResamplerSincTableBase<windowSize>::sinc_table 331 #define WSIZE ResamplerSincTableBase<windowSize>::WIDTH 332 #define SPZCSHIFT ResamplerSincTableBase<windowSize>::SAMPLES_PER_ZERO_CROSSING_SHIFT 333 334 #define SINC(x) \ 335 ((abs(x)>>16)>=(WSIZE-1) ? 0 : \ 336 (SINCTAB[abs(x) >> (16-SPZCSHIFT)] + \ 337 fpmul((SINCTAB[(abs(x) >> (16-SPZCSHIFT)) + 1] - \ 338 SINCTAB[abs(x) >> (16-SPZCSHIFT)]), \ 339 (abs(x) >> (16-SPZCSHIFT)) & 65535))) 340 341 // share sinc lookup table 342 template<mp_sint32 windowSize> 343 class ResamplerSincTableBase : public ChannelMixer::ResamplerBase 344 { 345 protected: 346 enum 347 { 348 WINDOWSIZE = windowSize, // must be even 349 WIDTH = (WINDOWSIZE / 2), 350 SAMPLES_PER_ZERO_CROSSING_SHIFT = 10, 351 SAMPLES_PER_ZERO_CROSSING = (1 << SAMPLES_PER_ZERO_CROSSING_SHIFT), 352 TABLESIZE = SAMPLES_PER_ZERO_CROSSING*WIDTH, 353 }; 354 355 static mp_sint32* sinc_table; 356 make_sinc()357 void make_sinc() 358 { 359 mp_sint32 i; 360 double temp,win_freq,win; 361 win_freq = M_PI / WIDTH / SAMPLES_PER_ZERO_CROSSING; 362 sinc_table[0] = 65536; 363 for (i=1;i<WIDTH * SAMPLES_PER_ZERO_CROSSING;i++) { 364 temp = (double) i * M_PI / SAMPLES_PER_ZERO_CROSSING; 365 win = 0.5 + 0.5 * cos(win_freq * i); // not quite true hamming window, but close 366 sinc_table[i] = (mp_sint32)(((sin(temp) / temp) * win) * 65536.0); 367 } 368 } 369 370 static bool tableInit; 371 ResamplerSincTableBase()372 ResamplerSincTableBase() 373 { 374 if (!tableInit) 375 { 376 sinc_table = new mp_sint32[TABLESIZE]; 377 make_sinc(); 378 tableInit = true; 379 } 380 } 381 }; 382 383 template<mp_sint32 windowSize> 384 bool ResamplerSincTableBase<windowSize>::tableInit = false; 385 template<mp_sint32 windowSize> 386 mp_sint32* ResamplerSincTableBase<windowSize>::sinc_table = NULL; 387 388 template<bool ramping, mp_sint32 windowSize, class bufferType, mp_uint32 shift> 389 class SincTableResamplerDummy : public ResamplerSincTableBase<windowSize> 390 { 391 public: addBlock(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)392 static inline void addBlock(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 393 { 394 const bufferType* sample = (const bufferType*)chn->sample; 395 396 mp_sint32 voll = chn->finalvoll; 397 mp_sint32 volr = chn->finalvolr; 398 399 const mp_sint32 rampFromVolStepL = ramping ? chn->rampFromVolStepL : 0; 400 const mp_sint32 rampFromVolStepR = ramping ? chn->rampFromVolStepR : 0; 401 402 mp_sint32 smppos = chn->smppos; 403 mp_sint32 smpposfrac = chn->smpposfrac; 404 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 405 const mp_sint32 rsmpadd = chn->rsmpadd; 406 407 const mp_sint32 flags = chn->flags; 408 const mp_sint32 loopstart = chn->loopstart; 409 const mp_sint32 loopend = chn->loopend; 410 const mp_sint32 loopendcopy = chn->loopendcopy; 411 const mp_sint32 smplen = chn->smplen; 412 413 mp_sint32 fixedtimefrac = chn->fixedtimefrac; 414 const mp_sint32 timeadd = chn->smpadd; 415 416 const mp_sint32 negflags = smpadd < 0 ? (flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) : ((flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) | ChannelMixer::MP_SAMPLE_BACKWARD); 417 const mp_sint32 posflags = smpadd > 0 ? (flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) : ((flags & ~ChannelMixer::MP_SAMPLE_BACKWARD) | ChannelMixer::MP_SAMPLE_BACKWARD); 418 419 mp_sint32 tmpsmppos; 420 mp_sint32 tmpflags; 421 mp_sint32 tmploopstart; 422 mp_sint32 tmploopend; 423 424 if (timeadd < 65536) 425 { 426 while (count--) 427 { 428 mp_sint32 result = 0; 429 430 tmpsmppos = smppos; 431 tmploopstart = loopstart; 432 tmploopend = loopend; 433 tmpflags = negflags; 434 // check whether we are outside loop points 435 // if that's the case we're treating the sample as a normal finite signal 436 // note that this is still not totally correct treatment 437 const bool outSideLoop = !(((flags & 3) && tmpsmppos >= loopstart && tmpsmppos < loopend)); 438 if (outSideLoop) 439 { 440 tmploopstart = 0; 441 tmploopend = smplen; 442 tmpflags &= ~3; 443 } 444 445 mp_sint32 time = fixedtimefrac; 446 if (!time && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 447 time = 65536; 448 449 mp_sint32 j; 450 for (j = 0; j<ResamplerSincTableBase<windowSize>::WIDTH; j++) 451 { 452 result += (sample[tmpsmppos] * SINC(time)) >> shift; 453 454 time+=65536; 455 advancePos(tmpsmppos, tmpflags, tmploopstart, tmploopend, loopendcopy); 456 if (!(tmpflags & ChannelMixer::MP_SAMPLE_PLAY)) 457 break; 458 } 459 460 tmpsmppos = smppos; 461 tmpflags = posflags; 462 if (outSideLoop) 463 tmpflags &= ~3; 464 465 time = fixedtimefrac; 466 if (!time && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 467 time = 65536; 468 469 for (j = 1; j<ResamplerSincTableBase<windowSize>::WIDTH; j++) 470 { 471 advancePos(tmpsmppos, tmpflags, tmploopstart, tmploopend, loopendcopy); 472 time-=65536; 473 if (!(tmpflags & ChannelMixer::MP_SAMPLE_PLAY)) 474 break; 475 476 result += (sample[tmpsmppos] * SINC(time)) >> shift; 477 } 478 479 480 (*buffer++)+=(((result)*(voll>>15))>>15); 481 (*buffer++)+=(((result)*(volr>>15))>>15); 482 483 if (ramping) 484 { 485 voll+=rampFromVolStepL; 486 volr+=rampFromVolStepR; 487 } 488 489 MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16); 490 fixedtimefrac=(fixedtimefrac+timeadd) & 65535; 491 } 492 } 493 else 494 { 495 while (count--) 496 { 497 mp_sint32 result = 0; 498 499 tmpsmppos = smppos; 500 tmploopstart = loopstart; 501 tmploopend = loopend; 502 tmpflags = negflags; 503 // check whether we are outside loop points 504 // if that's the case we're treating the sample as a normal finite signal 505 // note that this is still not totally correct treatment 506 const bool outSideLoop = !(((flags & 3) && tmpsmppos >= loopstart && tmpsmppos < loopend)); 507 if (outSideLoop) 508 { 509 tmploopstart = 0; 510 tmploopend = smplen; 511 tmpflags &= ~3; 512 } 513 514 mp_sint32 time = fpmul(fixedtimefrac, rsmpadd); 515 if (!time && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 516 time = 65536; 517 518 mp_sint32 j; 519 for (j = 0; j<ResamplerSincTableBase<windowSize>::WIDTH; j++) 520 { 521 result += (sample[tmpsmppos] * fpmul(SINC(time), rsmpadd)) >> shift; 522 523 advancePos(tmpsmppos, tmpflags, tmploopstart, tmploopend, loopendcopy); 524 time+=rsmpadd; 525 if (!(tmpflags & ChannelMixer::MP_SAMPLE_PLAY)) 526 break; 527 } 528 529 tmpsmppos = smppos; 530 tmpflags = posflags; 531 if (outSideLoop) 532 tmpflags &= ~3; 533 534 time = fpmul(fixedtimefrac, rsmpadd); 535 if (!time && (flags & ChannelMixer::MP_SAMPLE_BACKWARD)) 536 time = 65536; 537 538 for (j = 1; j<ResamplerSincTableBase<windowSize>::WIDTH; j++) 539 { 540 advancePos(tmpsmppos, tmpflags, tmploopstart, tmploopend, loopendcopy); 541 time-=rsmpadd; 542 if (!(tmpflags & ChannelMixer::MP_SAMPLE_PLAY)) 543 break; 544 545 result += (sample[tmpsmppos] * fpmul(SINC(time), rsmpadd)) >> shift; 546 } 547 548 (*buffer++)+=(((result)*(voll>>15))>>15); 549 (*buffer++)+=(((result)*(volr>>15))>>15); 550 551 if (ramping) 552 { 553 voll+=rampFromVolStepL; 554 volr+=rampFromVolStepR; 555 } 556 557 MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16); 558 fixedtimefrac=(fixedtimefrac+timeadd) & 65535; 559 } 560 } 561 562 chn->smppos = smppos; 563 chn->smpposfrac = smpposfrac; 564 565 chn->fixedtimefrac = fixedtimefrac; 566 567 if (ramping) 568 { 569 chn->finalvoll = voll; 570 chn->finalvolr = volr; 571 } 572 } 573 }; 574 575 template<bool ramping, mp_sint32 windowSize> 576 class ResamplerSincTable : public ResamplerSincTableBase<windowSize> 577 { 578 public: ResamplerSincTable()579 ResamplerSincTable() : 580 ResamplerSincTableBase<windowSize>() 581 { 582 } 583 isRamping()584 virtual bool isRamping() { return ramping; } supportsFullChecking()585 virtual bool supportsFullChecking() { return false; } supportsNoChecking()586 virtual bool supportsNoChecking() { return true; } 587 addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)588 virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 589 { 590 if (chn->flags & 4) 591 SincTableResamplerDummy<ramping, windowSize, mp_sword, 16>::addBlock(buffer, chn, count); 592 else 593 SincTableResamplerDummy<ramping, windowSize, mp_sbyte, 8>::addBlock(buffer, chn, count); 594 } 595 }; 596 597 #undef SINC 598 599 #undef SPZCSHIFT 600 #undef WSIZE 601 #undef SINCTAB 602 603 #undef fpmul 604