1 // license:BSD-3-Clause
2 // copyright-holders:Allard van der Bas
3 /***************************************************************************
4
5 Wiping sound driver (quick hack of the Namco sound driver)
6
7 used by wiping.cpp and clshroad.cpp
8
9 ***************************************************************************/
10
11 #include "emu.h"
12 #include "audio/wiping.h"
13
14 DEFINE_DEVICE_TYPE(WIPING_CUSTOM, wiping_sound_device, "wiping_sound", "Wiping Custom Sound")
15
wiping_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)16 wiping_sound_device::wiping_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
17 : device_t(mconfig, WIPING_CUSTOM, tag, owner, clock),
18 device_sound_interface(mconfig, *this),
19 m_last_channel(nullptr),
20 m_sound_prom(nullptr),
21 m_sound_rom(nullptr),
22 m_num_voices(0),
23 m_sound_enable(0),
24 m_stream(nullptr)
25 {
26 memset(m_channel_list, 0, sizeof(wp_sound_channel)*MAX_VOICES);
27 memset(m_soundregs, 0, sizeof(uint8_t)*0x4000);
28 }
29
30
31 //-------------------------------------------------
32 // device_start - device-specific startup
33 //-------------------------------------------------
34
device_start()35 void wiping_sound_device::device_start()
36 {
37 wp_sound_channel *voice;
38
39 /* get stream channels */
40 m_stream = stream_alloc(0, 1, clock()/2);
41
42 /* allocate a buffer to mix into - 1 second's worth should be more than enough */
43 m_mixer_buffer.resize(clock()/2);
44
45 /* extract globals from the interface */
46 m_num_voices = 8;
47 m_last_channel = m_channel_list + m_num_voices;
48
49 m_sound_rom = machine().root_device().memregion("samples")->base();
50 m_sound_prom = machine().root_device().memregion("soundproms")->base();
51
52 /* start with sound enabled, many games don't have a sound enable register */
53 m_sound_enable = 1;
54
55 /* reset all the voices */
56 for (voice = m_channel_list; voice < m_last_channel; voice++)
57 {
58 voice->frequency = 0;
59 voice->volume = 0;
60 voice->wave = &m_sound_prom[0];
61 voice->counter = 0;
62 }
63
64 save_item(NAME(m_soundregs));
65
66 for (int i = 0; i < MAX_VOICES; i++)
67 {
68 save_item(NAME(m_channel_list[i].frequency), i);
69 save_item(NAME(m_channel_list[i].counter), i);
70 save_item(NAME(m_channel_list[i].volume), i);
71 save_item(NAME(m_channel_list[i].oneshot), i);
72 save_item(NAME(m_channel_list[i].oneshotplaying), i);
73 }
74 }
75
76 /********************************************************************************/
77
sound_w(offs_t offset,uint8_t data)78 void wiping_sound_device::sound_w(offs_t offset, uint8_t data)
79 {
80 wp_sound_channel *voice;
81 int base;
82
83 /* update the streams */
84 m_stream->update();
85
86 /* set the register */
87 m_soundregs[offset] = data;
88
89 /* recompute all the voice parameters */
90 if (offset <= 0x3f)
91 {
92 for (base = 0, voice = m_channel_list; voice < m_last_channel; voice++, base += 8)
93 {
94 voice->frequency = m_soundregs[0x02 + base] & 0x0f;
95 voice->frequency = voice->frequency * 16 + ((m_soundregs[0x01 + base]) & 0x0f);
96 voice->frequency = voice->frequency * 16 + ((m_soundregs[0x00 + base]) & 0x0f);
97
98 voice->volume = m_soundregs[0x07 + base] & 0x0f;
99 if (m_soundregs[0x5 + base] & 0x0f)
100 {
101 voice->wave = &m_sound_rom[128 * (16 * (m_soundregs[0x5 + base] & 0x0f)
102 + (m_soundregs[0x2005 + base] & 0x0f))];
103 voice->oneshot = 1;
104 }
105 else
106 {
107 voice->wave = &m_sound_rom[16 * (m_soundregs[0x3 + base] & 0x0f)];
108 voice->oneshot = 0;
109 voice->oneshotplaying = 0;
110 }
111 }
112 }
113 else if (offset >= 0x2000)
114 {
115 voice = &m_channel_list[(offset & 0x3f)/8];
116 if (voice->oneshot)
117 {
118 voice->counter = 0;
119 voice->oneshotplaying = 1;
120 }
121 }
122 }
123
124 //-------------------------------------------------
125 // sound_stream_update - handle a stream update
126 //-------------------------------------------------
127
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)128 void wiping_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
129 {
130 auto &buffer = outputs[0];
131 wp_sound_channel *voice;
132 short *mix;
133 int i;
134
135 /* if no sound, we're done */
136 if (m_sound_enable == 0)
137 {
138 buffer.fill(0);
139 return;
140 }
141
142 /* zap the contents of the mixer buffer */
143 std::fill_n(&m_mixer_buffer[0], buffer.samples(), 0);
144
145 /* loop over each voice and add its contribution */
146 for (voice = m_channel_list; voice < m_last_channel; voice++)
147 {
148 int f = 16*voice->frequency;
149 int v = voice->volume;
150
151 /* only update if we have non-zero volume and frequency */
152 if (v && f)
153 {
154 const uint8_t *w = voice->wave;
155 int c = voice->counter;
156
157 mix = &m_mixer_buffer[0];
158
159 /* add our contribution */
160 for (i = 0; i < buffer.samples(); i++)
161 {
162 int offs;
163
164 c += f;
165
166 if (voice->oneshot)
167 {
168 if (voice->oneshotplaying)
169 {
170 offs = (c >> 15);
171 if (w[offs>>1] == 0xff)
172 {
173 voice->oneshotplaying = 0;
174 }
175
176 else
177 {
178 /* use full byte, first the high 4 bits, then the low 4 bits */
179 if (offs & 1)
180 *mix++ += ((w[offs>>1] & 0x0f) - 8) * v;
181 else
182 *mix++ += (((w[offs>>1]>>4) & 0x0f) - 8) * v;
183 }
184 }
185 }
186 else
187 {
188 offs = (c >> 15) & 0x1f;
189
190 /* use full byte, first the high 4 bits, then the low 4 bits */
191 if (offs & 1)
192 *mix++ += ((w[offs>>1] & 0x0f) - 8) * v;
193 else
194 *mix++ += (((w[offs>>1]>>4) & 0x0f) - 8) * v;
195 }
196 }
197
198 /* update the counter for this voice */
199 voice->counter = c;
200 }
201 }
202
203 /* mix it down */
204 mix = &m_mixer_buffer[0];
205 for (i = 0; i < buffer.samples(); i++)
206 buffer.put_int(i, *mix++, 128 * MAX_VOICES);
207 }
208