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