1 #include "Nes_Vrc7_Apu.h"
2
3 extern "C" {
4 #include "../vgmplay/VGMPlay/chips/emu2413.h"
5 }
6
7 #include <string.h>
8
9 #include "blargg_source.h"
10
11 static unsigned char vrc7_inst[(16 + 3) * 8] =
12 {
13 #include "../vgmplay/VGMPlay/chips/vrc7tone.h"
14 };
15
16 int const period = 36; // NES CPU clocks per FM clock
17
Nes_Vrc7_Apu()18 Nes_Vrc7_Apu::Nes_Vrc7_Apu()
19 {
20 opll = 0;
21 }
22
init()23 blargg_err_t Nes_Vrc7_Apu::init()
24 {
25 CHECK_ALLOC( opll = OPLL_new( 3579545, 3579545 / 72 ) );
26 OPLL_SetChipMode((OPLL *) opll, 1);
27 OPLL_setPatch((OPLL *) opll, vrc7_inst);
28
29 set_output( 0 );
30 volume( 1.0 );
31 reset();
32 return 0;
33 }
34
~Nes_Vrc7_Apu()35 Nes_Vrc7_Apu::~Nes_Vrc7_Apu()
36 {
37 if ( opll )
38 OPLL_delete( (OPLL *) opll );
39 }
40
set_output(Blip_Buffer * buf)41 void Nes_Vrc7_Apu::set_output( Blip_Buffer* buf )
42 {
43 for ( int i = 0; i < osc_count; ++i )
44 oscs [i].output = buf;
45 output_changed();
46 }
47
output_changed()48 void Nes_Vrc7_Apu::output_changed()
49 {
50 mono.output = oscs [0].output;
51 for ( int i = osc_count; --i; )
52 {
53 if ( mono.output != oscs [i].output )
54 {
55 mono.output = 0;
56 break;
57 }
58 }
59
60 if ( mono.output )
61 {
62 for ( int i = osc_count; --i; )
63 {
64 mono.last_amp += oscs [i].last_amp;
65 oscs [i].last_amp = 0;
66 }
67 }
68 }
69
reset()70 void Nes_Vrc7_Apu::reset()
71 {
72 addr = 0;
73 next_time = 0;
74 mono.last_amp = 0;
75
76 for ( int i = osc_count; --i >= 0; )
77 {
78 Vrc7_Osc& osc = oscs [i];
79 osc.last_amp = 0;
80 for ( int j = 0; j < 3; ++j )
81 osc.regs [j] = 0;
82 }
83
84 OPLL_reset( (OPLL *) opll );
85 }
86
write_reg(int data)87 void Nes_Vrc7_Apu::write_reg( int data )
88 {
89 addr = data;
90 }
91
write_data(blip_time_t time,int data)92 void Nes_Vrc7_Apu::write_data( blip_time_t time, int data )
93 {
94 int type = (addr >> 4) - 1;
95 int chan = addr & 15;
96 if ( (unsigned) type < 3 && chan < osc_count )
97 oscs [chan].regs [type] = data;
98 if ( addr < 0x08 )
99 inst [addr] = data;
100
101 if ( time > next_time )
102 run_until( time );
103 OPLL_writeIO( (OPLL *) opll, 0, addr );
104 OPLL_writeIO( (OPLL *) opll, 1, data );
105 }
106
end_frame(blip_time_t time)107 void Nes_Vrc7_Apu::end_frame( blip_time_t time )
108 {
109 if ( time > next_time )
110 run_until( time );
111
112 next_time -= time;
113 assert( next_time >= 0 );
114
115 for ( int i = osc_count; --i >= 0; )
116 {
117 Blip_Buffer* output = oscs [i].output;
118 if ( output )
119 output->set_modified();
120 }
121 }
122
save_snapshot(vrc7_snapshot_t * out) const123 void Nes_Vrc7_Apu::save_snapshot( vrc7_snapshot_t* out ) const
124 {
125 out->latch = addr;
126 out->delay = next_time;
127 for ( int i = osc_count; --i >= 0; )
128 {
129 for ( int j = 0; j < 3; ++j )
130 out->regs [i] [j] = oscs [i].regs [j];
131 }
132 memcpy( out->inst, inst, 8 );
133 }
134
load_snapshot(vrc7_snapshot_t const & in)135 void Nes_Vrc7_Apu::load_snapshot( vrc7_snapshot_t const& in )
136 {
137 assert( offsetof (vrc7_snapshot_t,delay) == 28 - 1 );
138
139 reset();
140 next_time = in.delay;
141 write_reg( in.latch );
142 int i;
143 for ( i = 0; i < osc_count; ++i )
144 {
145 for ( int j = 0; j < 3; ++j )
146 oscs [i].regs [j] = in.regs [i] [j];
147 }
148
149 memcpy( inst, in.inst, 8 );
150 for ( i = 0; i < 8; ++i )
151 {
152 OPLL_writeIO( (OPLL *) opll, 0, i );
153 OPLL_writeIO( (OPLL *) opll, 1, in.inst [i] );
154 }
155
156 for ( i = 0; i < 3; ++i )
157 {
158 for ( int j = 0; j < 6; ++j )
159 {
160 OPLL_writeIO( (OPLL *) opll, 0, 0x10 + i * 0x10 + j );
161 OPLL_writeIO( (OPLL *) opll, 1, oscs [j].regs [i] );
162 }
163 }
164 }
165
run_until(blip_time_t end_time)166 void Nes_Vrc7_Apu::run_until( blip_time_t end_time )
167 {
168 require( end_time > next_time );
169
170 blip_time_t time = next_time;
171 void* opll = this->opll; // cache
172 Blip_Buffer* const mono_output = mono.output;
173 e_int32 buffer [2];
174 e_int32* buffers[2] = {&buffer[0], &buffer[1]};
175 if ( mono_output )
176 {
177 // optimal case
178 do
179 {
180 OPLL_calc_stereo( (OPLL *) opll, buffers, 1, -1 );
181 int amp = buffer [0] + buffer [1];
182 int delta = amp - mono.last_amp;
183 if ( delta )
184 {
185 mono.last_amp = amp;
186 synth.offset_inline( time, delta, mono_output );
187 }
188 time += period;
189 }
190 while ( time < end_time );
191 }
192 else
193 {
194 mono.last_amp = 0;
195 do
196 {
197 OPLL_advance( (OPLL *) opll );
198 for ( int i = 0; i < osc_count; ++i )
199 {
200 Vrc7_Osc& osc = oscs [i];
201 if ( osc.output )
202 {
203 OPLL_calc_stereo( (OPLL *) opll, buffers, 1, i );
204 int amp = buffer [0] + buffer [1];
205 int delta = amp - osc.last_amp;
206 if ( delta )
207 {
208 osc.last_amp = amp;
209 synth.offset( time, delta, osc.output );
210 }
211 }
212 }
213 time += period;
214 }
215 while ( time < end_time );
216 }
217 next_time = time;
218 }
219