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 * ResamplerFast.h 32 * MilkyPlay 33 * 34 * Created by Peter Barth on 08.11.07. 35 * 36 * The goal of the resamplers in this file is to be as fast as possible. 37 * No compromises have been made for readability nor maintainability. 38 * (hence the use of some evil macro templates) 39 */ 40 41 #ifndef __RESAMPLERFAST_H__ 42 #define __RESAMPLERFAST_H__ 43 44 #include "ResamplerMacros.h" 45 46 /* 47 * Resampler without interpolation or ramping 48 */ 49 class ResamplerSimple : public ChannelMixer::ResamplerBase 50 { 51 public: isRamping()52 virtual bool isRamping() { return false; } supportsFullChecking()53 virtual bool supportsFullChecking() { return true; } supportsNoChecking()54 virtual bool supportsNoChecking() { return true; } 55 addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)56 virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 57 { 58 mp_sint32 voll = chn->finalvoll; 59 mp_sint32 volr = chn->finalvolr; 60 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_NORMAL, FULLMIXER_16BIT_NORMAL, 16, 0); 61 } 62 addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)63 virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 64 { 65 mp_sint32 voll = chn->finalvoll; 66 mp_sint32 volr = chn->finalvolr; 67 68 mp_sint32 smppos = chn->smppos; 69 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 70 const mp_sint32 basepos = smppos; 71 mp_sint32 posfixed = chn->smpposfrac; 72 73 mp_sint32 fp = smpadd*count; 74 MP_INCREASESMPPOS(chn->smppos,chn->smpposfrac,fp,16); 75 76 if ((voll == 0) && (volr == 0)) return; 77 78 mp_sint32 sd1,sd2; 79 80 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_NORMAL, NOCHECKMIXER_16BIT_NORMAL); 81 } 82 }; 83 84 /* 85 * Resampler without interpolation but with ramping. 86 */ 87 class ResamplerSimpleRamp : public ChannelMixer::ResamplerBase 88 { 89 public: isRamping()90 virtual bool isRamping() { return true; } supportsFullChecking()91 virtual bool supportsFullChecking() { return true; } supportsNoChecking()92 virtual bool supportsNoChecking() { return true; } 93 addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)94 virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 95 { 96 mp_sint32 voll = chn->finalvoll; 97 mp_sint32 volr = chn->finalvolr; 98 99 mp_sint32 rampFromVolStepL = chn->rampFromVolStepL; 100 mp_sint32 rampFromVolStepR = chn->rampFromVolStepR; 101 102 if (rampFromVolStepL || rampFromVolStepR) 103 { 104 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_NORMAL_RAMP(true), FULLMIXER_16BIT_NORMAL_RAMP(true), 16, 0); 105 } 106 else 107 { 108 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_NORMAL_RAMP(false), FULLMIXER_16BIT_NORMAL_RAMP(false), 16, 1); 109 } 110 111 chn->finalvoll = voll; 112 chn->finalvolr = volr; 113 } 114 addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)115 virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 116 { 117 mp_sint32 voll = chn->finalvoll; 118 mp_sint32 volr = chn->finalvolr; 119 120 mp_sint32 rampFromVolStepL = chn->rampFromVolStepL; 121 mp_sint32 rampFromVolStepR = chn->rampFromVolStepR; 122 123 mp_sint32 smppos = chn->smppos; 124 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 125 const mp_sint32 basepos = smppos; 126 mp_sint32 posfixed = chn->smpposfrac; 127 128 mp_sint32 fp = smpadd*count; 129 MP_INCREASESMPPOS(chn->smppos,chn->smpposfrac, fp, 16); 130 131 if ((voll == 0 && rampFromVolStepL == 0) && (volr == 0 && rampFromVolStepR == 0)) return; 132 133 mp_sint32 sd1,sd2; 134 135 if (rampFromVolStepL || rampFromVolStepR) 136 { 137 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_NORMAL_RAMP(true), NOCHECKMIXER_16BIT_NORMAL_RAMP(true)); 138 } 139 else 140 { 141 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_NORMAL_RAMP(false), NOCHECKMIXER_16BIT_NORMAL_RAMP(false)); 142 } 143 144 chn->finalvoll = voll; 145 chn->finalvolr = volr; 146 } 147 }; 148 149 /* 150 * Resampler using linear interpolation but without ramping. 151 */ 152 class ResamplerLerp : public ChannelMixer::ResamplerBase 153 { 154 public: isRamping()155 virtual bool isRamping() { return false; } supportsFullChecking()156 virtual bool supportsFullChecking() { return true; } supportsNoChecking()157 virtual bool supportsNoChecking() { return true; } 158 addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)159 virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 160 { 161 mp_sint32 voll = chn->finalvoll; 162 mp_sint32 volr = chn->finalvolr; 163 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP, FULLMIXER_16BIT_LERP, 16, 0); 164 } 165 addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)166 virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 167 { 168 mp_sint32 voll = chn->finalvoll; 169 mp_sint32 volr = chn->finalvolr; 170 171 mp_sint32 smppos = chn->smppos; 172 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 173 const mp_sint32 basepos = smppos; 174 mp_sint32 posfixed = chn->smpposfrac; 175 176 mp_sint32 fp = smpadd*count; 177 MP_INCREASESMPPOS(chn->smppos, chn->smpposfrac, fp, 16); 178 179 if ((voll == 0) && (volr == 0)) return; 180 181 mp_sint32 sd1,sd2; 182 183 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP,NOCHECKMIXER_16BIT_LERP); 184 } 185 }; 186 187 /* 188 * Resampler using linear interpolation and ramping. 189 * Also supports the low pass filter used by Impulse Tracker 190 */ 191 class ResamplerLerpRampFilter : public ChannelMixer::ResamplerBase 192 { 193 public: isRamping()194 virtual bool isRamping() { return true; } supportsFullChecking()195 virtual bool supportsFullChecking() { return true; } supportsNoChecking()196 virtual bool supportsNoChecking() { return true; } 197 addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)198 virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 199 { 200 mp_sint32 voll = chn->finalvoll; 201 mp_sint32 volr = chn->finalvolr; 202 203 mp_sint32 rampFromVolStepL = chn->rampFromVolStepL; 204 mp_sint32 rampFromVolStepR = chn->rampFromVolStepR; 205 206 // filter in use? 207 if (chn->cutoff != ChannelMixer::MP_INVALID_VALUE && chn->resonance != ChannelMixer::MP_INVALID_VALUE) 208 { 209 const mp_sint32 a = chn->a; 210 const mp_sint32 b = chn->b; 211 const mp_sint32 c = chn->c; 212 213 mp_sint32 currsample = chn->currsample; 214 mp_sint32 prevsample = chn->prevsample; 215 216 if (rampFromVolStepL || rampFromVolStepR) 217 { 218 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP_FILTER(true), FULLMIXER_16BIT_LERP_RAMP_FILTER(true), 16, 0); 219 } 220 else 221 { 222 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP_FILTER(false), FULLMIXER_16BIT_LERP_RAMP_FILTER(false), 16, 1); 223 } 224 225 chn->currsample = currsample; 226 chn->prevsample = prevsample; 227 } 228 // no filter 229 else 230 { 231 if (rampFromVolStepL || rampFromVolStepR) 232 { 233 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP(true), FULLMIXER_16BIT_LERP_RAMP(true), 16, 2); 234 } 235 else 236 { 237 FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP(false), FULLMIXER_16BIT_LERP_RAMP(false), 16, 3); 238 } 239 } 240 241 chn->finalvoll = voll; 242 chn->finalvolr = volr; 243 } 244 addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)245 virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count) 246 { 247 mp_sint32 voll = chn->finalvoll; 248 mp_sint32 volr = chn->finalvolr; 249 250 mp_sint32 rampFromVolStepL = chn->rampFromVolStepL; 251 mp_sint32 rampFromVolStepR = chn->rampFromVolStepR; 252 253 mp_sint32 smppos = chn->smppos; 254 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 255 const mp_sint32 basepos = smppos; 256 mp_sint32 posfixed = chn->smpposfrac; 257 258 mp_sint32 fp = smpadd*count; 259 MP_INCREASESMPPOS(chn->smppos, chn->smpposfrac, fp, 16); 260 261 mp_sint32 sd1,sd2; 262 263 // filter in use? 264 if (chn->cutoff != ChannelMixer::MP_INVALID_VALUE && chn->resonance != ChannelMixer::MP_INVALID_VALUE) 265 { 266 const mp_sint32 a = chn->a; 267 const mp_sint32 b = chn->b; 268 const mp_sint32 c = chn->c; 269 270 mp_sint32 currsample = chn->currsample; 271 mp_sint32 prevsample = chn->prevsample; 272 273 // check if ramping has to be performed 274 if (rampFromVolStepL || rampFromVolStepR) 275 { 276 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(true), NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(true)); 277 } 278 else 279 { 280 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(false), NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(false)); 281 } 282 283 chn->currsample = currsample; 284 chn->prevsample = prevsample; 285 } 286 // no filter 287 else 288 { 289 if ((voll == 0 && rampFromVolStepL == 0) && (volr == 0 && rampFromVolStepR == 0)) return; 290 291 // check if ramping has to be performed 292 if (rampFromVolStepL || rampFromVolStepR) 293 { 294 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(true), NOCHECKMIXER_16BIT_LERP_RAMP(true)); 295 } 296 else 297 { 298 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(false), NOCHECKMIXER_16BIT_LERP_RAMP(false)); 299 } 300 } 301 302 chn->finalvoll = voll; 303 chn->finalvolr = volr; 304 } 305 }; 306 307 /* 308 * only for testing purpose, some dummy resampler that can be used to 309 * play around etc. 310 */ 311 class ResamplerDummy : public ChannelMixer::ResamplerBase 312 { 313 public: isRamping()314 virtual bool isRamping() { return false; } 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 mp_sint32 voll = chn->finalvoll; 321 mp_sint32 volr = chn->finalvolr; 322 323 //const mp_sint32 rampFromVolStepL = chn->rampFromVolStepL; 324 //const mp_sint32 rampFromVolStepR = chn->rampFromVolStepR; 325 326 mp_sint32 smppos = chn->smppos; 327 mp_sint32 smpposfrac = chn->smpposfrac; 328 const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd; 329 330 mp_sint32 sd1,sd2; 331 332 const mp_sint32 flags = chn->flags; 333 const mp_sint32 loopstart = chn->loopstart; 334 const mp_sint32 loopend = chn->loopend; 335 const mp_sint32 smplen = chn->smplen; 336 337 mp_sint32 fixedtimefrac = chn->fixedtimefrac; 338 const mp_sint32 timeadd = chn->smpadd; 339 340 if (!(flags&4)) 341 { 342 const mp_sbyte* sample = chn->sample; 343 while (count--) 344 { 345 /*sd1 = sample[smppos] << 8; 346 sd2 = sample[smppos+1] << 8; 347 348 sd1 = ((sd1<<12)+(smpposfrac>>4)*(sd2-sd1))>>12; 349 350 (*buffer++)+=((sd1*(voll>>15))>>15); 351 (*buffer++)+=((sd1*(volr>>15))>>15); 352 353 voll+=rampFromVolStepL; 354 volr+=rampFromVolStepR; */ 355 356 mp_sint32 ofsf, v0, v1, v2, v3; 357 358 v1 = sample[smppos] << 8; 359 v2 = sample[smppos + 1] << 8; 360 361 v0 = sample[smppos - 1] << 8; 362 v3 = sample[smppos + 2] << 8; 363 ofsf = smpposfrac + 65536; 364 v3 += -3*v2 + 3*v1 - v0; 365 v3 = ChannelMixer::fixedmul(v3, (ofsf - 2*65536) / 6); 366 v3 += v2 - v1 - v1 + v0; 367 v3 = ChannelMixer::fixedmul(v3, (ofsf - 65536) >> 1); 368 v3 += v1 - v0; 369 v3 = ChannelMixer::fixedmul(v3, ofsf); 370 v3 += v0; 371 372 (*buffer++)+=((v3*(voll>>15))>>15); 373 (*buffer++)+=((v3*(volr>>15))>>15); 374 375 //voll+=rampFromVolStepL; 376 //volr+=rampFromVolStepR; 377 378 MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16); 379 } 380 } 381 else 382 { 383 const mp_sword* sample = (const mp_sword*)chn->sample; 384 while (count--) 385 { 386 mp_sint32 ofsf, v0, v1, v2, v3; 387 388 v1 = sample[smppos]; 389 v2 = sample[smppos + 1]; 390 391 v0 = sample[smppos - 1]; 392 v3 = sample[smppos + 2]; 393 ofsf = smpposfrac + 65536; 394 v3 += -3*v2 + 3*v1 - v0; 395 v3 = ChannelMixer::fixedmul(v3, (ofsf - 2*65536) / 6); 396 v3 += v2 - v1 - v1 + v0; 397 v3 = ChannelMixer::fixedmul(v3, (ofsf - 65536) >> 1); 398 v3 += v1 - v0; 399 v3 = ChannelMixer::fixedmul(v3, ofsf); 400 v3 += v0; 401 402 (*buffer++)+=((v3*(voll>>15))>>15); 403 (*buffer++)+=((v3*(volr>>15))>>15); 404 405 //voll+=rampFromVolStepL; 406 //volr+=rampFromVolStepR; 407 408 MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16); 409 } 410 } 411 412 chn->smppos = smppos; 413 chn->smpposfrac = smpposfrac; 414 415 chn->fixedtimefrac = fixedtimefrac; 416 417 /*if (!(chn->flags&4)) 418 { 419 const mp_sbyte* sample = chn->sample + basepos; 420 while (count--) 421 { 422 sd1 = sample[posfixed>>16]<<8; 423 sd2 = sample[(posfixed>>16)+1]<<8; 424 425 sd1 =((sd1<<12)+((posfixed>>4)&0xfff)*(sd2-sd1))>>12; 426 427 (*buffer++)+=((sd1*(voll>>15))>>15); 428 (*buffer++)+=((sd1*(volr>>15))>>15); 429 430 voll+=rampFromVolStepL; 431 volr+=rampFromVolStepR; 432 posfixed+=smpadd; 433 } 434 } 435 else 436 { 437 const mp_sword* sample = (const mp_sword*)chn->sample + basepos; 438 while (count--) 439 { 440 sd1 = sample[posfixed>>16]; 441 sd2 = sample[(posfixed>>16)+1]; 442 443 sd1 =((sd1<<12)+((posfixed>>4)&0xfff)*(sd2-sd1))>>12; 444 445 (*buffer++)+=((sd1*(voll>>15))>>15); 446 (*buffer++)+=((sd1*(volr>>15))>>15); 447 448 voll+=rampFromVolStepL; 449 volr+=rampFromVolStepR; 450 posfixed+=smpadd; 451 } 452 } */ 453 454 /* 455 if (chn->cutoff != MP_INVALID_VALUE && chn->resonance != MP_INVALID_VALUE) 456 { 457 const mp_sint32 a = chn->a; 458 const mp_sint32 b = chn->b; 459 const mp_sint32 c = chn->c; 460 461 mp_sint32 currsample = chn->currsample; 462 mp_sint32 prevsample = chn->prevsample; 463 464 // check if ramping has to be performed 465 if (rampFromVolStepL || rampFromVolStepR) 466 { 467 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(true),NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(true)); 468 } 469 else 470 { 471 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(false),NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(false)); 472 } 473 474 chn->currsample = currsample; 475 chn->prevsample = prevsample; 476 } 477 else 478 { 479 if ((voll == 0 && rampFromVolStepL == 0) && (volr == 0 && rampFromVolStepR == 0)) return; 480 481 // check if ramping has to be performed 482 if (rampFromVolStepL || rampFromVolStepR) 483 { 484 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(true),NOCHECKMIXER_16BIT_LERP_RAMP(true)); 485 } 486 else 487 { 488 NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(false),NOCHECKMIXER_16BIT_LERP_RAMP(false)); 489 } 490 }*/ 491 492 //chn->finalvoll = voll; 493 //chn->finalvolr = volr; 494 } 495 }; 496 497 #endif 498