1 // license:GPL-2.0+
2 // copyright-holders:Juergen Buchmueller
3 /****************************************************************************
4  *
5  * warpwarp.cpp
6  *
7  * sound driver
8  * juergen buchmueller <pullmoll@t-online.de>, jan 2000
9  *
10  ****************************************************************************/
11 
12 #include "emu.h"
13 #include "audio/warpwarp.h"
14 
15 
16 DEFINE_DEVICE_TYPE(WARPWARP_SOUND, warpwarp_sound_device, "warpwarp_sound", "Warp Warp Custom Sound")
17 
warpwarp_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)18 warpwarp_sound_device::warpwarp_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
19 	: device_t(mconfig, WARPWARP_SOUND, tag, owner, clock),
20 		device_sound_interface(mconfig, *this),
21 		m_decay(nullptr),
22 		m_channel(nullptr),
23 		m_sound_latch(0),
24 		m_music1_latch(0),
25 		m_music2_latch(0),
26 		m_sound_signal(0),
27 		m_sound_volume(0),
28 		m_sound_volume_timer(nullptr),
29 		m_music_signal(0),
30 		m_music_volume(0),
31 		m_music_volume_timer(nullptr),
32 		m_noise(0),
33 		m_vcarry(0),
34 		m_vcount(0),
35 		m_mcarry(0),
36 		m_mcount(0)
37 {
38 }
39 
40 
41 
42 //-------------------------------------------------
43 //  device_start - device-specific startup
44 //-------------------------------------------------
45 
device_start()46 void warpwarp_sound_device::device_start()
47 {
48 	m_decay = std::make_unique<int16_t[]>(32768);
49 
50 	for (int i = 0; i < 0x8000; i++)
51 		m_decay[0x7fff - i] = (int16_t) (0x7fff/exp(1.0*i/4096));
52 
53 	m_clock_16h = clock() / 3 / 2 / 16;
54 	m_clock_1v = clock() / 3 / 2 / 384;
55 	m_channel = stream_alloc(0, 1, m_clock_16h);
56 
57 	m_sound_volume_timer = timer_alloc(TIMER_SOUND_VOLUME_DECAY);
58 	m_music_volume_timer = timer_alloc(TIMER_MUSIC_VOLUME_DECAY);
59 
60 	save_item(NAME(m_sound_latch));
61 	save_item(NAME(m_music1_latch));
62 	save_item(NAME(m_music2_latch));
63 	save_item(NAME(m_sound_signal));
64 	save_item(NAME(m_sound_volume));
65 	save_item(NAME(m_music_signal));
66 	save_item(NAME(m_music_volume));
67 	save_item(NAME(m_noise));
68 	save_item(NAME(m_vcarry));
69 	save_item(NAME(m_vcount));
70 	save_item(NAME(m_mcarry));
71 	save_item(NAME(m_mcount));
72 }
73 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)74 void warpwarp_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
75 {
76 	switch (id)
77 	{
78 	case TIMER_SOUND_VOLUME_DECAY:
79 		if (--m_sound_volume < 0)
80 			m_sound_volume = 0;
81 		break;
82 
83 	case TIMER_MUSIC_VOLUME_DECAY:
84 		if (--m_music_volume < 0)
85 			m_music_volume = 0;
86 		break;
87 
88 	default:
89 		throw emu_fatalerror("Unknown id in warpwarp_sound_device::device_timer");
90 	}
91 }
92 
sound_w(u8 data)93 void warpwarp_sound_device::sound_w(u8 data)
94 {
95 	m_channel->update();
96 	m_sound_latch = data & 0x0f;
97 	m_sound_volume = 0x7fff; /* set sound_volume */
98 	m_noise = 0x0000;  /* reset noise shifter */
99 
100 	/* faster decay enabled? */
101 	if( m_sound_latch & 8 )
102 	{
103 		/*
104 		 * R85(?) is 10k, Rb is 0, C92 is 1uF
105 		 * charge time t1 = 0.693 * (R24 + Rb) * C57 -> 0.22176s
106 		 * discharge time t2 = 0.693 * (Rb) * C57 -> 0
107 		 * C90(?) is only charged via D17 (1N914), no discharge!
108 		 * Decay:
109 		 * discharge C90(?) (1uF) through R13||R14 (22k||47k)
110 		 * 0.639 * 15k * 1uF -> 0.9585s
111 		 */
112 		attotime period = attotime::from_hz(32768) * 95850 / 100000;
113 		m_sound_volume_timer->adjust(period, 0, period);
114 	}
115 	else
116 	{
117 		/*
118 		 * discharge only after R93 (100k) and through the 10k
119 		 * potentiometerin the amplifier section.
120 		 * 0.639 * 110k * 1uF -> 7.0290s
121 		 * ...but this is not very realistic for the game sound :(
122 		 * maybe there _is_ a discharge through the diode D17?
123 		 */
124 		//attotime period = attotime::from_hz(32768) * 702900 / 100000;
125 		attotime period = attotime::from_hz(32768) * 191700 / 100000;
126 		m_sound_volume_timer->adjust(period, 0, period);
127 	}
128 }
129 
music1_w(u8 data)130 void warpwarp_sound_device::music1_w(u8 data)
131 {
132 	m_channel->update();
133 	m_music1_latch = data & 0x3f;
134 }
135 
music2_w(u8 data)136 void warpwarp_sound_device::music2_w(u8 data)
137 {
138 	m_channel->update();
139 	m_music2_latch = data & 0x3f;
140 	m_music_volume = 0x7fff;
141 	/* fast decay enabled? */
142 	if( m_music2_latch & 0x10 )
143 	{
144 		/*
145 		 * Ra (R83?) is 10k, Rb is 0, C92 is 1uF
146 		 * charge time t1 = 0.693 * (Ra + Rb) * C -> 0.22176s
147 		 * discharge time is (nearly) zero, because Rb is zero
148 		 * C95(?) is only charged via D17, not discharged!
149 		 * Decay:
150 		 * discharge C95(?) (10uF) through R13||R14 (22k||47k)
151 		 * 0.639 * 15k * 10uF -> 9.585s
152 		 * ...I'm sure this is off by one number of magnitude :/
153 		 */
154 		attotime period = attotime::from_hz(32768) * 95850 / 100000;
155 		m_music_volume_timer->adjust(period, 0, period);
156 	}
157 	else
158 	{
159 		/*
160 		 * discharge through R14 (47k),
161 		 * discharge C95(?) (10uF) through R14 (47k)
162 		 * 0.639 * 47k * 10uF -> 30.033s
163 		 */
164 		//attotime period = attotime::from_hz(32768) * 3003300 / 100000;
165 		attotime period = attotime::from_hz(32768) * 300330 / 100000;
166 		m_music_volume_timer->adjust(period, 0, period);
167 	}
168 
169 }
170 
171 //-------------------------------------------------
172 //  sound_stream_update - handle a stream update
173 //-------------------------------------------------
174 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)175 void warpwarp_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
176 {
177 	auto &buffer = outputs[0];
178 
179 	for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
180 	{
181 		buffer.put_int(sampindex, m_sound_signal + m_music_signal, 32768 * 2);
182 
183 		/*
184 		 * The music signal is selected at a rate of 2H (1.536MHz) from the
185 		 * four bits of a 4 bit binary counter which is clocked with 16H,
186 		 * which is 192kHz, and is divided by 4 times (64 - music1_latch).
187 		 *  0 = 256 steps -> 750 Hz
188 		 *  1 = 252 steps -> 761.9 Hz
189 		 * ...
190 		 * 32 = 128 steps -> 1500 Hz
191 		 * ...
192 		 * 48 =  64 steps -> 3000 Hz
193 		 * ...
194 		 * 63 =   4 steps -> 48 kHz
195 		 */
196 
197 		m_mcarry -= m_clock_16h / (4 * (64 - m_music1_latch));
198 		while( m_mcarry < 0 )
199 		{
200 			m_mcarry += m_clock_16h;
201 			m_mcount++;
202 			m_music_signal = (m_mcount & ~m_music2_latch & 15) ? m_decay[m_music_volume] : 0;
203 			/* override by noise gate? */
204 			if( (m_music2_latch & 32) && (m_noise & 0x8000) )
205 				m_music_signal = m_decay[m_music_volume];
206 		}
207 
208 		/* clock 1V = 8kHz */
209 		m_vcarry -= m_clock_1v;
210 		while (m_vcarry < 0)
211 		{
212 			m_vcarry += m_clock_16h;
213 			m_vcount++;
214 
215 			/* noise is clocked with raising edge of 2V */
216 			if ((m_vcount & 3) == 2)
217 			{
218 				/* bit0 = bit0 ^ !bit10 */
219 				if ((m_noise & 1) == ((m_noise >> 10) & 1))
220 					m_noise = (m_noise << 1) | 1;
221 				else
222 					m_noise = m_noise << 1;
223 			}
224 
225 			switch (m_sound_latch & 7)
226 			{
227 			case 0: /* 4V */
228 				m_sound_signal = (m_vcount & 0x04) ? m_decay[m_sound_volume] : 0;
229 				break;
230 			case 1: /* 8V */
231 				m_sound_signal = (m_vcount & 0x08) ? m_decay[m_sound_volume] : 0;
232 				break;
233 			case 2: /* 16V */
234 				m_sound_signal = (m_vcount & 0x10) ? m_decay[m_sound_volume] : 0;
235 				break;
236 			case 3: /* 32V */
237 				m_sound_signal = (m_vcount & 0x20) ? m_decay[m_sound_volume] : 0;
238 				break;
239 			case 4: /* TONE1 */
240 				m_sound_signal = !(m_vcount & 0x01) && !(m_vcount & 0x10) ? m_decay[m_sound_volume] : 0;
241 				break;
242 			case 5: /* TONE2 */
243 				m_sound_signal = !(m_vcount & 0x02) && !(m_vcount & 0x20) ? m_decay[m_sound_volume] : 0;
244 				break;
245 			case 6: /* TONE3 */
246 				m_sound_signal = !(m_vcount & 0x04) && !(m_vcount & 0x40) ? m_decay[m_sound_volume] : 0;
247 				break;
248 			default: /* NOISE */
249 				/* QH of 74164 #4V */
250 				m_sound_signal = (m_noise & 0x8000) ? m_decay[m_sound_volume] : 0;
251 			}
252 
253 		}
254 	}
255 }
256