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