Mercurial > audlegacy-plugins
comparison src/console/Spc_Dsp.cxx @ 316:fb513e10174e trunk
[svn] - merge libconsole-blargg into mainline libconsole:
+ obsoletes plugins-ugly:sapplug
author | nenolod |
---|---|
date | Thu, 30 Nov 2006 19:54:33 -0800 |
parents | 3da1b8942b8b |
children | 986f098da058 |
comparison
equal
deleted
inserted
replaced
315:2294f3a6f136 | 316:fb513e10174e |
---|---|
1 | 1 // Game_Music_Emu 0.5.1. http://www.slack.net/~ant/ |
2 // Game_Music_Emu 0.3.0. http://www.slack.net/~ant/ | |
3 | 2 |
4 // Based on Brad Martin's OpenSPC DSP emulator | 3 // Based on Brad Martin's OpenSPC DSP emulator |
5 | 4 |
6 #include "Spc_Dsp.h" | 5 #include "Spc_Dsp.h" |
7 | 6 |
7 #include "blargg_endian.h" | |
8 #include <string.h> | 8 #include <string.h> |
9 | |
10 #include "blargg_endian.h" | |
11 | 9 |
12 /* Copyright (C) 2002 Brad Martin */ | 10 /* Copyright (C) 2002 Brad Martin */ |
13 /* Copyright (C) 2004-2006 Shay Green. This module is free software; you | 11 /* Copyright (C) 2004-2006 Shay Green. This module is free software; you |
14 can redistribute it and/or modify it under the terms of the GNU Lesser | 12 can redistribute it and/or modify it under the terms of the GNU Lesser |
15 General Public License as published by the Free Software Foundation; either | 13 General Public License as published by the Free Software Foundation; either |
16 version 2.1 of the License, or (at your option) any later version. This | 14 version 2.1 of the License, or (at your option) any later version. This |
17 module is distributed in the hope that it will be useful, but WITHOUT ANY | 15 module is distributed in the hope that it will be useful, but WITHOUT ANY |
18 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
19 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for | 17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
20 more details. You should have received a copy of the GNU Lesser General | 18 details. You should have received a copy of the GNU Lesser General Public |
21 Public License along with this module; if not, write to the Free Software | 19 License along with this module; if not, write to the Free Software Foundation, |
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
23 | 21 |
24 #include BLARGG_SOURCE_BEGIN | 22 #include "blargg_source.h" |
23 | |
24 #ifdef BLARGG_ENABLE_OPTIMIZER | |
25 #include BLARGG_ENABLE_OPTIMIZER | |
26 #endif | |
25 | 27 |
26 Spc_Dsp::Spc_Dsp( uint8_t* ram_ ) : ram( ram_ ) | 28 Spc_Dsp::Spc_Dsp( uint8_t* ram_ ) : ram( ram_ ) |
27 { | 29 { |
28 set_gain( 1.0 ); | 30 set_gain( 1.0 ); |
29 mute_voices( 0 ); | 31 mute_voices( 0 ); |
30 disable_surround( false ); | 32 disable_surround( false ); |
31 | 33 |
32 BOOST_STATIC_ASSERT( sizeof (g) == register_count && sizeof (voice) == register_count ); | 34 BOOST_STATIC_ASSERT( sizeof (g) == register_count && sizeof (voice) == register_count ); |
35 blargg_verify_byte_order(); | |
33 } | 36 } |
34 | 37 |
35 void Spc_Dsp::mute_voices( int mask ) | 38 void Spc_Dsp::mute_voices( int mask ) |
36 { | 39 { |
37 for ( int i = 0; i < voice_count; i++ ) | 40 for ( int i = 0; i < voice_count; i++ ) |
65 { | 68 { |
66 require( (unsigned) i < register_count ); | 69 require( (unsigned) i < register_count ); |
67 | 70 |
68 reg [i] = data; | 71 reg [i] = data; |
69 int high = i >> 4; | 72 int high = i >> 4; |
70 switch ( i & 0x0f ) | 73 switch ( i & 0x0F ) |
71 { | 74 { |
72 // voice volume | 75 // voice volume |
73 case 0: | 76 case 0: |
74 case 1: { | 77 case 1: { |
75 short* volume = voice_state [high].volume; | 78 short* volume = voice_state [high].volume; |
76 int left = (int8_t) reg [i & ~1]; | 79 int left = (int8_t) reg [i & ~1]; |
77 int right = (int8_t) reg [i | 1]; | 80 int right = (int8_t) reg [i | 1]; |
78 volume [0] = left; | 81 volume [0] = left; |
79 volume [1] = right; | 82 volume [1] = right; |
80 // kill surround only if signs of volumes differ | 83 // kill surround only if enabled and signs of volumes differ |
81 if ( left * right < surround_threshold ) | 84 if ( left * right < surround_threshold ) |
82 { | 85 { |
83 if ( left < 0 ) | 86 if ( left < 0 ) |
84 volume [0] = -left; | 87 volume [0] = -left; |
85 else | 88 else |
87 } | 90 } |
88 break; | 91 break; |
89 } | 92 } |
90 | 93 |
91 // fir coefficients | 94 // fir coefficients |
92 case 0x0f: | 95 case 0x0F: |
93 fir_coeff [high] = (int8_t) data; // sign-extend | 96 fir_coeff [high] = (int8_t) data; // sign-extend |
94 break; | 97 break; |
95 } | 98 } |
96 } | 99 } |
97 | 100 |
98 // This table is for envelope timing. It represents the number of counts | 101 // This table is for envelope timing. It represents the number of counts |
99 // that should be subtracted from the counter each sample period (32kHz). | 102 // that should be subtracted from the counter each sample period (32kHz). |
100 // The counter starts at 30720 (0x7800). Each count divides exactly into | 103 // The counter starts at 30720 (0x7800). Each count divides exactly into |
101 // 0x7800 without remainder. | 104 // 0x7800 without remainder. |
102 const int env_rate_init = 0x7800; | 105 const int env_rate_init = 0x7800; |
103 static const short env_rates [0x20] = | 106 static short const env_rates [0x20] = |
104 { | 107 { |
105 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, | 108 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, |
106 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, | 109 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, |
107 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, | 110 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, |
108 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 | 111 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 |
190 | 193 |
191 case state_sustain: | 194 case state_sustain: |
192 // Docs: "SR [is multiplied] by the fixed value 1-1/256." | 195 // Docs: "SR [is multiplied] by the fixed value 1-1/256." |
193 // Multiplying ENVX by 255/256 every time SUSTAIN is | 196 // Multiplying ENVX by 255/256 every time SUSTAIN is |
194 // updated. | 197 // updated. |
195 cnt -= env_rates [raw_voice.adsr [1] & 0x1f]; | 198 cnt -= env_rates [raw_voice.adsr [1] & 0x1F]; |
196 if ( cnt <= 0 ) | 199 if ( cnt <= 0 ) |
197 { | 200 { |
198 cnt = env_rate_init; | 201 cnt = env_rate_init; |
199 envx -= ((envx - 1) >> 8) + 1; | 202 envx -= ((envx - 1) >> 8) + 1; |
200 voice.envx = envx; | 203 voice.envx = envx; |
338 { | 341 { |
339 noise_count = env_rate_init; | 342 noise_count = env_rate_init; |
340 | 343 |
341 noise_amp = BOOST::int16_t (noise * 2); | 344 noise_amp = BOOST::int16_t (noise * 2); |
342 | 345 |
346 // TODO: switch to Galios style | |
343 int feedback = (noise << 13) ^ (noise << 14); | 347 int feedback = (noise << 13) ^ (noise << 14); |
344 noise = (feedback & 0x4000) | (noise >> 1); | 348 noise = (feedback & 0x4000) | (noise >> 1); |
345 } | 349 } |
346 } | 350 } |
347 | 351 |
348 // What is the expected behavior when pitch modulation is enabled on | 352 // What is the expected behavior when pitch modulation is enabled on |
349 // voice 0? Jurassic Park 2 does this. Assume 0 for now. | 353 // voice 0? Jurassic Park 2 does this. Assume 0 for now. |
350 long prev_outx = 0; | 354 blargg_long prev_outx = 0; |
351 | 355 |
352 int echol = 0; | 356 int echol = 0; |
353 int echor = 0; | 357 int echor = 0; |
354 int left = 0; | 358 int left = 0; |
355 int right = 0; | 359 int right = 0; |
365 keys |= vbit; | 369 keys |= vbit; |
366 voice.addr = GET_LE16( sd [raw_voice.waveform].start ); | 370 voice.addr = GET_LE16( sd [raw_voice.waveform].start ); |
367 voice.block_remain = 1; | 371 voice.block_remain = 1; |
368 voice.envx = 0; | 372 voice.envx = 0; |
369 voice.block_header = 0; | 373 voice.block_header = 0; |
370 voice.fraction = 0x3fff; // decode three samples immediately | 374 voice.fraction = 0x3FFF; // decode three samples immediately |
371 voice.interp0 = 0; // BRR decoder filter uses previous two samples | 375 voice.interp0 = 0; // BRR decoder filter uses previous two samples |
372 voice.interp1 = 0; | 376 voice.interp1 = 0; |
373 | 377 |
374 // NOTE: Real SNES does *not* appear to initialize the | 378 // NOTE: Real SNES does *not* appear to initialize the |
375 // envelope counter to anything in particular. The first | 379 // envelope counter to anything in particular. The first |
472 delta = (delta >> 14) & ~0x7FF; | 476 delta = (delta >> 14) & ~0x7FF; |
473 | 477 |
474 // One, two and three point IIR filters | 478 // One, two and three point IIR filters |
475 int smp1 = voice.interp0; | 479 int smp1 = voice.interp0; |
476 int smp2 = voice.interp1; | 480 int smp2 = voice.interp1; |
477 switch ( (voice.block_header >> 2) & 3 ) | 481 if ( voice.block_header & 8 ) |
478 { | 482 { |
479 case 0: | 483 delta += smp1; |
480 break; | 484 delta -= smp2 >> 1; |
481 | 485 if ( !(voice.block_header & 4) ) |
482 case 1: | 486 { |
483 delta += smp1 >> 1; | 487 delta += (-smp1 - (smp1 >> 1)) >> 5; |
484 delta += (-smp1) >> 5; | |
485 break; | |
486 | |
487 case 2: | |
488 delta += smp1; | |
489 delta += (-(smp1 + (smp1 >> 1))) >> 5; | |
490 delta -= smp2 >> 1; | |
491 delta += smp2 >> 5; | 488 delta += smp2 >> 5; |
492 break; | 489 } |
493 | 490 else |
494 case 3: | 491 { |
495 delta += smp1; | 492 delta += (-smp1 * 13) >> 7; |
496 delta += (-(smp1 + (smp1 << 2) + (smp1 << 3))) >> 7; | |
497 delta -= smp2 >> 1; | |
498 delta += (smp2 + (smp2 >> 1)) >> 4; | 493 delta += (smp2 + (smp2 >> 1)) >> 4; |
499 break; | 494 } |
495 } | |
496 else if ( voice.block_header & 4 ) | |
497 { | |
498 delta += smp1 >> 1; | |
499 delta += (-smp1) >> 5; | |
500 } | 500 } |
501 | 501 |
502 voice.interp3 = voice.interp2; | 502 voice.interp3 = voice.interp2; |
503 voice.interp2 = smp2; | 503 voice.interp2 = smp2; |
504 voice.interp1 = smp1; | 504 voice.interp1 = smp1; |
511 rate = (rate * (prev_outx + 32768)) >> 15; | 511 rate = (rate * (prev_outx + 32768)) >> 15; |
512 | 512 |
513 // Gaussian interpolation using most recent 4 samples | 513 // Gaussian interpolation using most recent 4 samples |
514 int index = voice.fraction >> 2 & 0x3FC; | 514 int index = voice.fraction >> 2 & 0x3FC; |
515 voice.fraction = (voice.fraction & 0x0FFF) + rate; | 515 voice.fraction = (voice.fraction & 0x0FFF) + rate; |
516 const BOOST::int16_t* table = (BOOST::int16_t*) ((char*) gauss + index); | 516 const BOOST::int16_t* table = (BOOST::int16_t const*) ((char const*) gauss + index); |
517 const BOOST::int16_t* table2 = (BOOST::int16_t*) ((char*) gauss + (255*4 - index)); | 517 const BOOST::int16_t* table2 = (BOOST::int16_t const*) ((char const*) gauss + (255*4 - index)); |
518 int s = ((table [0] * voice.interp3) >> 12) + | 518 int s = ((table [0] * voice.interp3) >> 12) + |
519 ((table [1] * voice.interp2) >> 12); | 519 ((table [1] * voice.interp2) >> 12) + |
520 s += ((table2 [1] * voice.interp1) >> 12) + | 520 ((table2 [1] * voice.interp1) >> 12); |
521 // to do: should clamp here | 521 s = (BOOST::int16_t) (s * 2); |
522 ((table2 [0] * voice.interp0) >> 12); | 522 s += (table2 [0] * voice.interp0) >> 11 & ~1; |
523 int output = noise_amp; // noise is rarely used | 523 int output = clamp_16( s ); |
524 if ( !(g.noise_enables & vbit) ) | 524 if ( g.noise_enables & vbit ) |
525 output = clamp_16( s * 2 ); | 525 output = noise_amp; |
526 | 526 |
527 // scale output and set outx values | 527 // scale output and set outx values |
528 output = (output * envx) >> 11 & ~1; | 528 output = (output * envx) >> 11 & ~1; |
529 | 529 |
530 // output and apply muting (by setting voice.enabled to 31) | 530 // output and apply muting (by setting voice.enabled to 31) |
531 // if voice is externally disabled (not a SNES feature) | 531 // if voice is externally disabled (not a SNES feature) |
532 int l = (voice.volume [0] * output) >> voice.enabled; | 532 int l = (voice.volume [0] * output) >> voice.enabled; |
533 int r = (voice.volume [1] * output) >> voice.enabled; | 533 int r = (voice.volume [1] * output) >> voice.enabled; |
534 prev_outx = output; | 534 prev_outx = output; |
535 raw_voice.outx = output >> 8; | 535 raw_voice.outx = int8_t (output >> 8); |
536 if ( g.echo_ons & vbit ) | 536 if ( g.echo_ons & vbit ) |
537 { | 537 { |
538 echol += l; | 538 echol += l; |
539 echor += r; | 539 echor += r; |
540 } | 540 } |
541 left += l; | 541 left += l; |
542 right += r; | 542 right += r; |
543 } | 543 } |
544 // end of channel loop | 544 // end of channel loop |
545 | 545 |
546 // main volume control | 546 // main volume control |
561 | 561 |
562 // put samples in history ring buffer | 562 // put samples in history ring buffer |
563 const int fir_offset = this->fir_offset; | 563 const int fir_offset = this->fir_offset; |
564 short (*fir_pos) [2] = &fir_buf [fir_offset]; | 564 short (*fir_pos) [2] = &fir_buf [fir_offset]; |
565 this->fir_offset = (fir_offset + 7) & 7; // move backwards one step | 565 this->fir_offset = (fir_offset + 7) & 7; // move backwards one step |
566 fir_pos [0] [0] = fb_left; | 566 fir_pos [0] [0] = (short) fb_left; |
567 fir_pos [0] [1] = fb_right; | 567 fir_pos [0] [1] = (short) fb_right; |
568 fir_pos [8] [0] = fb_left; // duplicate at +8 eliminates wrap checking below | 568 fir_pos [8] [0] = (short) fb_left; // duplicate at +8 eliminates wrap checking below |
569 fir_pos [8] [1] = fb_right; | 569 fir_pos [8] [1] = (short) fb_right; |
570 | 570 |
571 // FIR | 571 // FIR |
572 fb_left = fb_left * fir_coeff [7] + | 572 fb_left = fb_left * fir_coeff [7] + |
573 fir_pos [1] [0] * fir_coeff [6] + | 573 fir_pos [1] [0] * fir_coeff [6] + |
574 fir_pos [2] [0] * fir_coeff [5] + | 574 fir_pos [2] [0] * fir_coeff [5] + |
606 left = clamp_16( left ); | 606 left = clamp_16( left ); |
607 right = clamp_16( right ); | 607 right = clamp_16( right ); |
608 | 608 |
609 int mute = g.flags & 0x40; | 609 int mute = g.flags & 0x40; |
610 | 610 |
611 out_buf [0] = left; | 611 out_buf [0] = (short) left; |
612 out_buf [1] = right; | 612 out_buf [1] = (short) right; |
613 out_buf += 2; | 613 out_buf += 2; |
614 | 614 |
615 // muting | 615 // muting |
616 if ( mute ) | 616 if ( mute ) |
617 { | 617 { |
661 2, 504, 2, 499, 2, 495, 2, 491, 2, 486, 1, 482, 1, 477, 1, 473, | 661 2, 504, 2, 499, 2, 495, 2, 491, 2, 486, 1, 482, 1, 477, 1, 473, |
662 1, 469, 1, 464, 1, 460, 1, 456, 1, 451, 1, 447, 1, 443, 1, 439, | 662 1, 469, 1, 464, 1, 460, 1, 456, 1, 451, 1, 447, 1, 443, 1, 439, |
663 0, 434, 0, 430, 0, 426, 0, 422, 0, 418, 0, 414, 0, 410, 0, 405, | 663 0, 434, 0, 430, 0, 426, 0, 422, 0, 418, 0, 414, 0, 410, 0, 405, |
664 0, 401, 0, 397, 0, 393, 0, 389, 0, 385, 0, 381, 0, 378, 0, 374, | 664 0, 401, 0, 397, 0, 393, 0, 389, 0, 385, 0, 381, 0, 378, 0, 374, |
665 }; | 665 }; |
666 |