Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Nes_Fme7_Apu.h
2 views
1
2
// Sunsoft FME-7 sound emulator
3
4
// Nes_Emu 0.7.0
5
6
#ifndef NES_FME7_APU_H
7
#define NES_FME7_APU_H
8
9
#include "blargg_common.h"
10
#include "Blip_Buffer.h"
11
12
struct fme7_apu_state_t
13
{
14
enum { reg_count = 14 };
15
BOOST::uint8_t regs [reg_count];
16
BOOST::uint8_t phases [3]; // 0 or 1
17
BOOST::uint8_t latch;
18
BOOST::uint16_t delays [3]; // a, b, c
19
};
20
BOOST_STATIC_ASSERT( sizeof (fme7_apu_state_t) == 24 );
21
22
class Nes_Fme7_Apu : private fme7_apu_state_t {
23
public:
24
Nes_Fme7_Apu();
25
26
// See Nes_Apu.h for reference
27
void reset();
28
void volume( double );
29
void treble_eq( blip_eq_t const& );
30
void output( Blip_Buffer* );
31
enum { osc_count = 3 };
32
void osc_output( int index, Blip_Buffer* );
33
void end_frame( blip_time_t );
34
void save_state( fme7_apu_state_t* ) const;
35
void load_state( fme7_apu_state_t const& );
36
37
// Mask and addresses of registers
38
enum { addr_mask = 0xe000 };
39
enum { data_addr = 0xe000 };
40
enum { latch_addr = 0xc000 };
41
42
// (addr & addr_mask) == latch_addr
43
void write_latch( int );
44
45
// (addr & addr_mask) == data_addr
46
void write_data( blip_time_t, int data );
47
48
// End of public interface
49
private:
50
// noncopyable
51
Nes_Fme7_Apu( const Nes_Fme7_Apu& );
52
Nes_Fme7_Apu& operator = ( const Nes_Fme7_Apu& );
53
54
static unsigned char amp_table [16];
55
56
struct {
57
Blip_Buffer* output;
58
int last_amp;
59
} oscs [osc_count];
60
blip_time_t last_time;
61
62
enum { amp_range = 192 }; // can be any value; this gives best error/quality tradeoff
63
Blip_Synth<blip_good_quality,1> synth;
64
65
void run_until( blip_time_t );
66
};
67
68
inline void Nes_Fme7_Apu::volume( double v )
69
{
70
synth.volume( 0.38 / amp_range * v ); // to do: fine-tune
71
}
72
73
inline void Nes_Fme7_Apu::treble_eq( blip_eq_t const& eq )
74
{
75
synth.treble_eq( eq );
76
}
77
78
inline void Nes_Fme7_Apu::osc_output( int i, Blip_Buffer* buf )
79
{
80
assert( (unsigned) i < osc_count );
81
oscs [i].output = buf;
82
}
83
84
inline void Nes_Fme7_Apu::output( Blip_Buffer* buf )
85
{
86
for ( int i = 0; i < osc_count; i++ )
87
osc_output( i, buf );
88
}
89
90
inline Nes_Fme7_Apu::Nes_Fme7_Apu()
91
{
92
output( NULL );
93
volume( 1.0 );
94
reset();
95
}
96
97
inline void Nes_Fme7_Apu::write_latch( int data ) { latch = data; }
98
99
inline void Nes_Fme7_Apu::write_data( blip_time_t time, int data )
100
{
101
if ( (unsigned) latch >= reg_count )
102
{
103
#ifdef dprintf
104
dprintf( "FME7 write to %02X (past end of sound registers)\n", (int) latch );
105
#endif
106
return;
107
}
108
109
run_until( time );
110
regs [latch] = data;
111
}
112
113
inline void Nes_Fme7_Apu::end_frame( blip_time_t time )
114
{
115
if ( time > last_time )
116
run_until( time );
117
118
assert( last_time >= time );
119
last_time -= time;
120
}
121
122
inline void Nes_Fme7_Apu::save_state( fme7_apu_state_t* out ) const
123
{
124
*out = *this;
125
}
126
127
inline void Nes_Fme7_Apu::load_state( fme7_apu_state_t const& in )
128
{
129
reset();
130
fme7_apu_state_t* state = this;
131
*state = in;
132
}
133
134
#endif
135
136
137