/gme/Nes_Fme7_Apu.h

http://game-music-emu.googlecode.com/ · C++ Header · 131 lines · 99 code · 25 blank · 7 comment · 3 complexity · f795b52db6697a36a776d4a897957030 MD5 · raw file

  1. // Sunsoft FME-7 sound emulator
  2. // Game_Music_Emu 0.5.5
  3. #ifndef NES_FME7_APU_H
  4. #define NES_FME7_APU_H
  5. #include "blargg_common.h"
  6. #include "Blip_Buffer.h"
  7. struct fme7_apu_state_t
  8. {
  9. enum { reg_count = 14 };
  10. BOOST::uint8_t regs [reg_count];
  11. BOOST::uint8_t phases [3]; // 0 or 1
  12. BOOST::uint8_t latch;
  13. BOOST::uint16_t delays [3]; // a, b, c
  14. };
  15. class Nes_Fme7_Apu : private fme7_apu_state_t {
  16. public:
  17. // See Nes_Apu.h for reference
  18. void reset();
  19. void volume( double );
  20. void treble_eq( blip_eq_t const& );
  21. void output( Blip_Buffer* );
  22. enum { osc_count = 3 };
  23. void osc_output( int index, Blip_Buffer* );
  24. void end_frame( blip_time_t );
  25. void save_state( fme7_apu_state_t* ) const;
  26. void load_state( fme7_apu_state_t const& );
  27. // Mask and addresses of registers
  28. enum { addr_mask = 0xE000 };
  29. enum { data_addr = 0xE000 };
  30. enum { latch_addr = 0xC000 };
  31. // (addr & addr_mask) == latch_addr
  32. void write_latch( int );
  33. // (addr & addr_mask) == data_addr
  34. void write_data( blip_time_t, int data );
  35. public:
  36. Nes_Fme7_Apu();
  37. BLARGG_DISABLE_NOTHROW
  38. private:
  39. // noncopyable
  40. Nes_Fme7_Apu( const Nes_Fme7_Apu& );
  41. Nes_Fme7_Apu& operator = ( const Nes_Fme7_Apu& );
  42. static unsigned char const amp_table [16];
  43. struct {
  44. Blip_Buffer* output;
  45. int last_amp;
  46. } oscs [osc_count];
  47. blip_time_t last_time;
  48. enum { amp_range = 192 }; // can be any value; this gives best error/quality tradeoff
  49. Blip_Synth<blip_good_quality,1> synth;
  50. void run_until( blip_time_t );
  51. };
  52. inline void Nes_Fme7_Apu::volume( double v )
  53. {
  54. synth.volume( 0.38 / amp_range * v ); // to do: fine-tune
  55. }
  56. inline void Nes_Fme7_Apu::treble_eq( blip_eq_t const& eq )
  57. {
  58. synth.treble_eq( eq );
  59. }
  60. inline void Nes_Fme7_Apu::osc_output( int i, Blip_Buffer* buf )
  61. {
  62. assert( (unsigned) i < osc_count );
  63. oscs [i].output = buf;
  64. }
  65. inline void Nes_Fme7_Apu::output( Blip_Buffer* buf )
  66. {
  67. for ( int i = 0; i < osc_count; i++ )
  68. osc_output( i, buf );
  69. }
  70. inline Nes_Fme7_Apu::Nes_Fme7_Apu()
  71. {
  72. output( NULL );
  73. volume( 1.0 );
  74. reset();
  75. }
  76. inline void Nes_Fme7_Apu::write_latch( int data ) { latch = data; }
  77. inline void Nes_Fme7_Apu::write_data( blip_time_t time, int data )
  78. {
  79. if ( (unsigned) latch >= reg_count )
  80. {
  81. #ifdef debug_printf
  82. debug_printf( "FME7 write to %02X (past end of sound registers)\n", (int) latch );
  83. #endif
  84. return;
  85. }
  86. run_until( time );
  87. regs [latch] = data;
  88. }
  89. inline void Nes_Fme7_Apu::end_frame( blip_time_t time )
  90. {
  91. if ( time > last_time )
  92. run_until( time );
  93. assert( last_time >= time );
  94. last_time -= time;
  95. }
  96. inline void Nes_Fme7_Apu::save_state( fme7_apu_state_t* out ) const
  97. {
  98. *out = *this;
  99. }
  100. inline void Nes_Fme7_Apu::load_state( fme7_apu_state_t const& in )
  101. {
  102. reset();
  103. fme7_apu_state_t* state = this;
  104. *state = in;
  105. }
  106. #endif