1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /**************************************************************************************
4 
5   Wonderswan sound emulation
6 
7   Wilbert Pol
8 
9   Sound emulation is preliminary and not complete
10 
11 
12 The noise taps and behavior are the same as the Virtual Boy.
13 
14 **************************************************************************************/
15 
16 #include "emu.h"
17 #include "wswan.h"
18 
19 
20 // device type definition
21 DEFINE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device, "wswan_sound", "WonderSwan Custom Sound")
22 
23 
24 //**************************************************************************
25 //  LIVE DEVICE
26 //**************************************************************************
27 
28 //-------------------------------------------------
29 //  wswan_sound_device - constructor
30 //-------------------------------------------------
31 
wswan_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)32 wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
33 	: device_t(mconfig, WSWAN_SND, tag, owner, clock),
34 		device_sound_interface(mconfig, *this),
35 		device_rom_interface(mconfig, *this),
36 		m_channel(nullptr),
37 		m_sweep_step(0),
38 		m_sweep_time(0),
39 		m_sweep_count(0),
40 		m_noise_type(0),
41 		m_noise_reset(0),
42 		m_noise_enable(0),
43 		m_noise_output(0),
44 		m_sample_address(0),
45 		m_audio2_voice(0),
46 		m_audio3_sweep(0),
47 		m_audio4_noise(0),
48 		m_mono(0),
49 		m_output_volume(0),
50 		m_external_stereo(0),
51 		m_external_speaker(0),
52 		m_noise_shift(0),
53 		m_master_volume(0)
54 {
55 }
56 
57 constexpr int clk_div = 64;
58 
59 //-------------------------------------------------
60 //  device_start - device-specific startup
61 //-------------------------------------------------
62 
device_start()63 void wswan_sound_device::device_start()
64 {
65 	m_channel = stream_alloc(0, 2, clock() / clk_div);
66 
67 	save_item(NAME(m_sweep_step));
68 	save_item(NAME(m_sweep_time));
69 	save_item(NAME(m_sweep_count));
70 	save_item(NAME(m_noise_type));
71 	save_item(NAME(m_noise_reset));
72 	save_item(NAME(m_noise_enable));
73 	save_item(NAME(m_sample_address));
74 	save_item(NAME(m_audio2_voice));
75 	save_item(NAME(m_audio3_sweep));
76 	save_item(NAME(m_audio4_noise));
77 	save_item(NAME(m_mono));
78 	save_item(NAME(m_output_volume));
79 	save_item(NAME(m_external_stereo));
80 	save_item(NAME(m_external_speaker));
81 	save_item(NAME(m_noise_shift));
82 	save_item(NAME(m_master_volume));
83 
84 	save_item(NAME(m_audio1.freq));
85 	save_item(NAME(m_audio1.period));
86 	save_item(NAME(m_audio1.pos));
87 	save_item(NAME(m_audio1.vol_left));
88 	save_item(NAME(m_audio1.vol_right));
89 	save_item(NAME(m_audio1.on));
90 	save_item(NAME(m_audio1.offset));
91 	save_item(NAME(m_audio1.signal));
92 
93 	save_item(NAME(m_audio2.freq));
94 	save_item(NAME(m_audio2.period));
95 	save_item(NAME(m_audio2.pos));
96 	save_item(NAME(m_audio2.vol_left));
97 	save_item(NAME(m_audio2.vol_right));
98 	save_item(NAME(m_audio2.on));
99 	save_item(NAME(m_audio2.offset));
100 	save_item(NAME(m_audio2.signal));
101 
102 	save_item(NAME(m_audio3.freq));
103 	save_item(NAME(m_audio3.period));
104 	save_item(NAME(m_audio3.pos));
105 	save_item(NAME(m_audio3.vol_left));
106 	save_item(NAME(m_audio3.vol_right));
107 	save_item(NAME(m_audio3.on));
108 	save_item(NAME(m_audio3.offset));
109 	save_item(NAME(m_audio3.signal));
110 
111 	save_item(NAME(m_audio4.freq));
112 	save_item(NAME(m_audio4.period));
113 	save_item(NAME(m_audio4.pos));
114 	save_item(NAME(m_audio4.vol_left));
115 	save_item(NAME(m_audio4.vol_right));
116 	save_item(NAME(m_audio4.on));
117 	save_item(NAME(m_audio4.offset));
118 	save_item(NAME(m_audio4.signal));
119 }
120 
device_clock_changed()121 void wswan_sound_device::device_clock_changed()
122 {
123 	m_channel->set_sample_rate(clock() / clk_div);
124 }
125 
rom_bank_updated()126 void wswan_sound_device::rom_bank_updated()
127 {
128 	m_channel->update();
129 }
130 
131 //-------------------------------------------------
132 //  device_reset
133 //-------------------------------------------------
134 
device_reset()135 void wswan_sound_device::device_reset()
136 {
137 	m_audio1.on = 0;
138 	m_audio1.signal = 0;
139 	m_audio1.offset = 0;
140 	m_audio1.pos = 0;
141 	m_audio2.on = 0;
142 	m_audio2.signal = 0;
143 	m_audio2.offset = 0;
144 	m_audio2.pos = 0;
145 	m_audio3.on = 0;
146 	m_audio3.signal = 0;
147 	m_audio3.offset = 0;
148 	m_audio3.pos = 0;
149 	m_audio4.on = 0;
150 	m_audio4.signal = 0;
151 	m_audio4.offset = 0;
152 	m_audio4.pos = 0;
153 	m_noise_output = 0;
154 }
155 
fetch_sample(int channel,int offset)156 int wswan_sound_device::fetch_sample(int channel, int offset)
157 {
158 	uint8_t b = read_byte(m_sample_address + ((channel & 3) << 4) + ((offset & 0x1f) >> 1));
159 
160 	if (offset & 1)
161 		return b >> 4;
162 	else
163 		return b & 0xf;
164 }
165 
166 //-------------------------------------------------
167 //  sound_stream_update - handle a stream update
168 //-------------------------------------------------
169 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)170 void wswan_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
171 {
172 	s32 sample, left, right;
173 
174 	auto &outputl = outputs[0];
175 	auto &outputr = outputs[1];
176 	for (int sampindex = 0; sampindex < outputl.samples(); sampindex++)
177 	{
178 		left = right = 0;
179 
180 		if ( m_audio1.on )
181 		{
182 			sample = m_audio1.signal;
183 			m_audio1.pos += clk_div;
184 			if (m_audio1.pos >= m_audio1.period)
185 			{
186 				m_audio1.pos -= m_audio1.period;
187 				m_audio1.signal = fetch_sample(0, m_audio1.offset++);
188 			}
189 			left += m_audio1.vol_left * sample;
190 			right += m_audio1.vol_right * sample;
191 		}
192 
193 		if ( m_audio2.on )
194 		{
195 			if ( m_audio2_voice )
196 			{
197 				uint8_t voice_data = m_audio2.vol_left << 4 | m_audio2.vol_right;
198 				left += voice_data * (m_master_volume & 0x0f);
199 				right += voice_data * (m_master_volume & 0x0f);
200 			}
201 			else
202 			{
203 				sample = m_audio2.signal;
204 				m_audio2.pos += clk_div;
205 				if (m_audio2.pos >= m_audio2.period)
206 				{
207 					m_audio2.pos -= m_audio2.period;
208 					m_audio2.signal = fetch_sample(1, m_audio2.offset++);
209 				}
210 				left += m_audio2.vol_left * sample;
211 				right += m_audio2.vol_right * sample;
212 			}
213 		}
214 
215 		if ( m_audio3.on )
216 		{
217 			sample = m_audio3.signal;
218 			m_audio3.pos += clk_div;
219 			if (m_audio3.pos >= m_audio3.period)
220 			{
221 				m_audio3.pos -= m_audio3.period;
222 				m_audio3.signal = fetch_sample(2, m_audio3.offset++);
223 			}
224 			if ( m_audio3_sweep && m_sweep_time )
225 			{
226 				m_sweep_count += clk_div;
227 				if ( m_sweep_count >= m_sweep_time )
228 				{
229 					m_sweep_count -= m_sweep_time;
230 					m_audio3.freq += m_sweep_step;
231 					m_audio3.freq &= 0x7ff;
232 					m_audio3.period = 2048 - m_audio3.freq;
233 				}
234 			}
235 			left += m_audio3.vol_left * sample;
236 			right += m_audio3.vol_right * sample;
237 		}
238 
239 		if ( m_audio4.on )
240 		{
241 			sample = m_audio4.signal;
242 			m_audio4.pos += clk_div;
243 			if (m_audio4.pos >= m_audio4.period)
244 			{
245 				if (m_audio4_noise)
246 					m_audio4.signal = m_noise_output ? 0xf : 0;
247 				else
248 					m_audio4.signal = fetch_sample(3, m_audio4.offset++);
249 
250 				m_audio4.pos -= m_audio4.period;
251 
252 				if (m_noise_reset)
253 				{
254 					m_noise_reset = 0;
255 					m_noise_shift = 0;
256 					m_noise_output = 0;
257 				}
258 
259 				if (m_noise_enable)
260 				{
261 					static int shift_bit[] = { 14, 10, 13, 4, 8, 6, 9, 11 };
262 
263 					m_noise_output = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1;
264 					m_noise_shift = m_noise_shift << 1 | m_noise_output;
265 				}
266 			}
267 			left += m_audio4.vol_left * sample;
268 			right += m_audio4.vol_right * sample;
269 		}
270 
271 		outputl.put_int(sampindex, left, 32768 >> 5);
272 		outputr.put_int(sampindex, right, 32768 >> 5);
273 	}
274 }
275 
276 
wswan_ch_set_freq(CHAN * ch,uint16_t freq)277 void wswan_sound_device::wswan_ch_set_freq( CHAN *ch, uint16_t freq )
278 {
279 	freq &= 0x7ff;  // docs say freq is 11bits and a few games (Morita Shougi, World Stadium + others) write 0x800 causing a divide by 0 crash
280 	ch->freq = freq;
281 	ch->period = 2048 - freq;
282 }
283 
port_w(offs_t offset,uint8_t data)284 void wswan_sound_device::port_w(offs_t offset, uint8_t data)
285 {
286 	m_channel->update();
287 
288 	switch( offset )
289 	{
290 		case 0x80:              /* Audio 1 freq (lo) */
291 			wswan_ch_set_freq(&m_audio1, (m_audio1.freq & 0xff00) | data);
292 			break;
293 
294 		case 0x81:              /* Audio 1 freq (hi) */
295 			wswan_ch_set_freq(&m_audio1, (data << 8 ) | (m_audio1.freq & 0x00ff));
296 			break;
297 
298 		case 0x82:              /* Audio 2 freq (lo) */
299 			wswan_ch_set_freq(&m_audio2, (m_audio2.freq & 0xff00) | data);
300 			break;
301 
302 		case 0x83:              /* Audio 2 freq (hi) */
303 			wswan_ch_set_freq(&m_audio2, (data << 8 ) | (m_audio2.freq & 0x00ff));
304 			break;
305 
306 		case 0x84:              /* Audio 3 freq (lo) */
307 			wswan_ch_set_freq(&m_audio3, (m_audio3.freq & 0xff00) | data);
308 			break;
309 
310 		case 0x85:              /* Audio 3 freq (hi) */
311 			wswan_ch_set_freq(&m_audio3, (data << 8) | (m_audio3.freq & 0x00ff));
312 			break;
313 
314 		case 0x86:              /* Audio 4 freq (lo) */
315 			wswan_ch_set_freq(&m_audio4, (m_audio4.freq & 0xff00) | data);
316 			break;
317 
318 		case 0x87:              /* Audio 4 freq (hi) */
319 			wswan_ch_set_freq(&m_audio4, (data << 8) | (m_audio4.freq & 0x00ff));
320 			break;
321 
322 		case 0x88:              /* Audio 1 volume */
323 			m_audio1.vol_left = ( data & 0xF0 ) >> 4;
324 			m_audio1.vol_right = data & 0x0F;
325 			break;
326 
327 		case 0x89:              /* Audio 2 volume */
328 			m_audio2.vol_left = ( data & 0xF0 ) >> 4;
329 			m_audio2.vol_right = data & 0x0F;
330 			break;
331 
332 		case 0x8A:              /* Audio 3 volume */
333 			m_audio3.vol_left = ( data & 0xF0 ) >> 4;
334 			m_audio3.vol_right = data & 0x0F;
335 			break;
336 
337 		case 0x8B:              /* Audio 4 volume */
338 			m_audio4.vol_left = ( data & 0xF0 ) >> 4;
339 			m_audio4.vol_right = data & 0x0F;
340 			break;
341 
342 		case 0x8C:              /* Sweep step */
343 			m_sweep_step = (int8_t)data;
344 			break;
345 
346 		case 0x8D:              /* Sweep time */
347 			m_sweep_time = 8192 * (data + 1);
348 			break;
349 
350 		case 0x8E:              /* Noise control */
351 			m_noise_type = data & 0x07;
352 			m_noise_reset = ( data & 0x08 ) >> 3;
353 			m_noise_enable = ( data & 0x10 ) >> 4;
354 			break;
355 
356 		case 0x8F:              /* Sample location */
357 			m_sample_address = data << 6;
358 			break;
359 
360 		case 0x90:              /* Audio control */
361 			m_audio1.on = data & 0x01;
362 			m_audio2.on = ( data & 0x02 ) >> 1;
363 			m_audio3.on = ( data & 0x04 ) >> 2;
364 			m_audio4.on = ( data & 0x08 ) >> 3;
365 			m_audio2_voice = ( data & 0x20 ) >> 5;
366 			m_audio3_sweep = ( data & 0x40 ) >> 6;
367 			m_audio4_noise = ( data & 0x80 ) >> 7;
368 			break;
369 
370 		case 0x91:              /* Audio output */
371 			m_mono = data & 0x01;
372 			m_output_volume = ( data & 0x06 ) >> 1;
373 			m_external_stereo = ( data & 0x08 ) >> 3;
374 			m_external_speaker = 1;
375 			break;
376 
377 		case 0x92:              /* Noise counter shift register (lo) */
378 			m_noise_shift = ( m_noise_shift & 0xFF00 ) | data;
379 			break;
380 
381 		case 0x93:              /* Noise counter shift register (hi) */
382 			m_noise_shift = ( ( data & 0x7f ) << 8 ) | ( m_noise_shift & 0x00FF );
383 			break;
384 
385 		case 0x94:              /* Master volume */
386 			m_master_volume = data;
387 			break;
388 	}
389 }
390