1 #include "Opl_Apu.h"
2 
3 #include "blargg_source.h"
4 
5 extern "C" {
6 #include "../vgmplay/VGMPlay/chips/mamedef.h"
7 #include "../vgmplay/VGMPlay/chips/emu2413.h"
8 #include "../vgmplay/VGMPlay/chips/fmopl.h"
9 }
10 
11 static unsigned char vrc7_inst[(16 + 3) * 8] =
12 {
13 #include "../vgmplay/VGMPlay/chips/vrc7tone.h"
14 };
15 
Opl_Apu()16 Opl_Apu::Opl_Apu() { opl = 0; opl_memory = 0; }
17 
init(long clock,long rate,blip_time_t period,type_t type)18 blargg_err_t Opl_Apu::init( long clock, long rate, blip_time_t period, type_t type )
19 {
20 	type_ = type;
21 	clock_ = clock;
22 	rate_ = rate;
23 	period_ = period;
24 	set_output( 0, 0 );
25 	volume( 1.0 );
26 	switch (type)
27 	{
28 	case type_opll:
29 	case type_msxmusic:
30 	case type_smsfmunit:
31 		opl = OPLL_new( (uint32_t) clock, (uint32_t) rate );
32         OPLL_SetChipMode( (OPLL *) opl, 0);
33 		break;
34 
35 	case type_vrc7:
36 		opl = OPLL_new( (uint32_t) clock, (uint32_t) rate );
37         OPLL_SetChipMode((OPLL *) opl, 1 );
38         OPLL_setPatch((OPLL *) opl, vrc7_inst);
39 		break;
40 
41 	case type_opl:
42 		opl = ym3526_init( (uint32_t) clock, (uint32_t) rate );
43 		break;
44 
45 	case type_msxaudio:
46 		//logfile = fopen("c:\\temp\\msxaudio.log", "wb");
47 		opl = y8950_init( (uint32_t) clock, (uint32_t) rate );
48 		opl_memory = malloc( 32768 );
49 		y8950_set_delta_t_memory( opl, opl_memory, 32768 );
50 		break;
51 
52 	case type_opl2:
53 		opl = ym3812_init( (uint32_t) clock, (uint32_t) rate );
54 		break;
55 	}
56 	reset();
57 	return 0;
58 }
59 
~Opl_Apu()60 Opl_Apu::~Opl_Apu()
61 {
62 	if (opl)
63 	{
64 		switch (type_)
65 		{
66 		case type_opll:
67 		case type_msxmusic:
68 		case type_smsfmunit:
69 		case type_vrc7:
70 			OPLL_delete( (OPLL *) opl );
71 			break;
72 
73 		case type_opl:
74 			ym3526_shutdown( opl );
75 			break;
76 
77 		case type_msxaudio:
78 			y8950_shutdown( opl );
79 			free( opl_memory );
80 			//fclose( logfile );
81 			break;
82 
83 		case type_opl2:
84 			ym3812_shutdown( opl );
85 			break;
86 		}
87 	}
88 }
89 
reset()90 void Opl_Apu::reset()
91 {
92 	addr = 0;
93 	next_time = 0;
94 	last_amp = 0;
95 
96 	switch (type_)
97 	{
98 	case type_opll:
99 	case type_msxmusic:
100 	case type_smsfmunit:
101 	case type_vrc7:
102 		OPLL_reset( (OPLL *) opl );
103 		break;
104 
105 	case type_opl:
106 		ym3526_reset_chip( opl );
107 		break;
108 
109 	case type_msxaudio:
110 		y8950_reset_chip( opl );
111 		break;
112 
113 	case type_opl2:
114 		ym3812_reset_chip( opl );
115 		break;
116 	}
117 }
118 
write_data(blip_time_t time,int data)119 void Opl_Apu::write_data( blip_time_t time, int data )
120 {
121 	run_until( time );
122 	switch (type_)
123 	{
124 	case type_opll:
125 	case type_msxmusic:
126 	case type_smsfmunit:
127 	case type_vrc7:
128 		OPLL_writeIO( (OPLL *) opl, 0, addr );
129 		OPLL_writeIO( (OPLL *) opl, 1, data );
130 		break;
131 
132 	case type_opl:
133 		ym3526_write( opl, 0, addr );
134 		ym3526_write( opl, 1, data );
135 		break;
136 
137 	case type_msxaudio:
138 		/*if ( addr >= 7 && addr <= 7 + 11 )
139 		{
140 			unsigned char temp [2] = { addr - 7, data };
141 			fwrite( &temp, 1, 2, logfile );
142 		}*/
143 		y8950_write( opl, 0, addr );
144 		y8950_write( opl, 1, data );
145 		break;
146 
147 	case type_opl2:
148 		ym3812_write( opl, 0, addr );
149 		ym3812_write( opl, 1, data );
150 		break;
151 	}
152 }
153 
read(blip_time_t time,int port)154 int Opl_Apu::read( blip_time_t time, int port )
155 {
156 	run_until( time );
157 	switch (type_)
158 	{
159 	case type_opll:
160 	case type_msxmusic:
161 	case type_smsfmunit:
162 	case type_vrc7:
163         return port ? 0xFF : 0;
164 
165 	case type_opl:
166 		return ym3526_read( opl, port );
167 
168 	case type_msxaudio:
169 		{
170 			int ret = y8950_read( opl, port );
171 			/*unsigned char temp [2] = { port + 0x80, ret };
172 			fwrite( &temp, 1, 2, logfile );*/
173 			return ret;
174 		}
175 
176 	case type_opl2:
177 		return ym3812_read( opl, port );
178 	}
179 
180 	return 0;
181 }
182 
end_frame(blip_time_t time)183 void Opl_Apu::end_frame( blip_time_t time )
184 {
185 	run_until( time );
186 	next_time -= time;
187 
188 	if ( output_ )
189 		output_->set_modified();
190 }
191 
run_until(blip_time_t end_time)192 void Opl_Apu::run_until( blip_time_t end_time )
193 {
194 	if ( end_time > next_time )
195 	{
196 		blip_time_t time_delta = end_time - next_time;
197 		blip_time_t time = next_time;
198 		unsigned count = time_delta / period_ + 1;
199 		switch (type_)
200 		{
201 		case type_opll:
202 		case type_msxmusic:
203 		case type_smsfmunit:
204 		case type_vrc7:
205 			{
206 				e_int32 bufMO[ 1024 ];
207 				e_int32 bufRO[ 1024 ];
208 				e_int32 * buffers[2] = { bufMO, bufRO };
209 
210 				while ( count > 0 )
211 				{
212 					unsigned todo = count;
213 					if ( todo > 1024 ) todo = 1024;
214 					OPLL_calc_stereo( (OPLL *) opl, buffers, todo, -1 );
215 
216 					if ( output_ )
217 					{
218 						int last_amp = this->last_amp;
219 						for ( unsigned i = 0; i < todo; i++ )
220 						{
221 							int amp = bufMO [i] + bufRO [i];
222 							int delta = amp - last_amp;
223 							if ( delta )
224 							{
225 								last_amp = amp;
226 								synth.offset_inline( time, delta, output_ );
227 							}
228 							time += period_;
229 						}
230 						this->last_amp = last_amp;
231 					}
232 					else time += period_ * todo;
233 
234 					count -= todo;
235 				}
236 			}
237 			break;
238 
239 		case type_opl:
240 		case type_msxaudio:
241 		case type_opl2:
242 			{
243 				OPLSAMPLE bufL[ 1024 ];
244                 OPLSAMPLE bufR[ 1024 ];
245                 OPLSAMPLE* buffers[2] = {bufL, bufR};
246 
247 				while ( count > 0 )
248 				{
249 					unsigned todo = count;
250 					if ( todo > 1024 ) todo = 1024;
251 					switch (type_)
252 					{
253 					case type_opl:      ym3526_update_one( opl, buffers, todo ); break;
254 					case type_msxaudio: y8950_update_one( opl, buffers, todo ); break;
255 					case type_opl2:     ym3812_update_one( opl, buffers, todo ); break;
256 					default: break;
257 					}
258 
259 					if ( output_ )
260 					{
261 						int last_amp = this->last_amp;
262 						for ( unsigned i = 0; i < todo; i++ )
263 						{
264 							int amp = bufL [i] + bufR [i];
265 							int delta = amp - last_amp;
266 							if ( delta )
267 							{
268 								last_amp = amp;
269 								synth.offset_inline( time, delta, output_ );
270 							}
271 							time += period_;
272 						}
273 						this->last_amp = last_amp;
274 					}
275 					else time += period_ * todo;
276 
277 					count -= todo;
278 				}
279 			}
280 			break;
281 		}
282 		next_time = time;
283 	}
284 }