1 // license:GPL-2.0+
2 // copyright-holders:Juergen Buchmueller
3 /****************************************************************************
4  *
5  * geebee.cpp
6  *
7  * sound driver
8  * juergen buchmueller <pullmoll@t-online.de>, jan 2000
9  *
10  ****************************************************************************/
11 
12 #include "emu.h"
13 #include "audio/geebee.h"
14 
15 
16 DEFINE_DEVICE_TYPE(GEEBEE_SOUND, geebee_sound_device, "geebee_sound", "Gee Bee Custom Sound")
17 
geebee_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)18 geebee_sound_device::geebee_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
19 	: device_t(mconfig, GEEBEE_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_sound_signal(0),
25 		m_volume(0),
26 		m_volume_timer(nullptr),
27 		m_noise(0),
28 		m_vcount(0)
29 {
30 }
31 
32 
33 //-------------------------------------------------
34 //  device_start - device-specific startup
35 //-------------------------------------------------
36 
device_start()37 void geebee_sound_device::device_start()
38 {
39 	m_decay = std::make_unique<uint16_t[]>(32768);
40 
41 	for (int i = 0; i < 0x8000; i++)
42 		m_decay[0x7fff - i] = (int16_t) (0x7fff/exp(1.0*i/4096));
43 
44 	/* 1V = HSYNC = 18.432MHz / 3 / 2 / 384 = 8000Hz */
45 	m_channel = stream_alloc(0, 1, clock() / 3 / 2 / 384);
46 	m_vcount = 0;
47 
48 	m_volume_timer = timer_alloc(TIMER_VOLUME_DECAY);
49 
50 	save_item(NAME(m_sound_latch));
51 	save_item(NAME(m_sound_signal));
52 	save_item(NAME(m_volume));
53 	save_item(NAME(m_noise));
54 	save_item(NAME(m_vcount));
55 }
56 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)57 void geebee_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
58 {
59 	switch (id)
60 	{
61 	case TIMER_VOLUME_DECAY:
62 		if (--m_volume < 0)
63 			m_volume = 0;
64 		break;
65 
66 	default:
67 		throw emu_fatalerror("Unknown id in geebee_device::device_timer");
68 	}
69 }
70 
sound_w(u8 data)71 void geebee_sound_device::sound_w(u8 data)
72 {
73 	m_channel->update();
74 	m_sound_latch = data;
75 	m_volume = 0x7fff; /* set volume */
76 	m_noise = 0x0000;  /* reset noise shifter */
77 	/* faster decay enabled? */
78 	if( m_sound_latch & 8 )
79 	{
80 		/*
81 		 * R24 is 10k, Rb is 0, C57 is 1uF
82 		 * charge time t1 = 0.693 * (R24 + Rb) * C57 -> 0.22176s
83 		 * discharge time t2 = 0.693 * (Rb) * C57 -> 0
84 		 * Then C33 is only charged via D6 (1N914), not discharged!
85 		 * Decay:
86 		 * discharge C33 (1uF) through R50 (22k) -> 0.14058s
87 		 */
88 		attotime period = attotime::from_hz(32768) * 14058 / 100000;
89 		m_volume_timer->adjust(period, 0, period);
90 	}
91 	else
92 	{
93 		/*
94 		 * discharge only after R49 (100k) in the amplifier section,
95 		 * so the volume shouldn't very fast and only when the signal
96 		 * is gated through 6N (4066).
97 		 * I can only guess here that the decay should be slower,
98 		 * maybe half as fast?
99 		 */
100 		attotime period = attotime::from_hz(32768) * 29060 / 100000;
101 		m_volume_timer->adjust(period, 0, period);
102 	}
103 }
104 
105 //-------------------------------------------------
106 //  sound_stream_update - handle a stream update
107 //-------------------------------------------------
108 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)109 void geebee_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
110 {
111 	auto &buffer = outputs[0];
112 
113 	for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
114 	{
115 		buffer.put_int(sampindex, m_sound_signal, 32768);
116 		/* 1V = HSYNC = 18.432MHz / 3 / 2 / 384 = 8000Hz */
117 		{
118 			m_vcount++;
119 			/* noise clocked with raising edge of 2V */
120 			if ((m_vcount & 3) == 2)
121 			{
122 				/* bit0 = bit0 ^ !bit10 */
123 				if ((m_noise & 1) == ((m_noise >> 10) & 1))
124 					m_noise = ((m_noise << 1) & 0xfffe) | 1;
125 				else
126 					m_noise = (m_noise << 1) & 0xfffe;
127 			}
128 			switch (m_sound_latch & 7)
129 			{
130 			case 0: /* 4V */
131 				m_sound_signal = (m_vcount & 0x04) ? m_decay[m_volume] : 0;
132 				break;
133 			case 1: /* 8V */
134 				m_sound_signal = (m_vcount & 0x08) ? m_decay[m_volume] : 0;
135 				break;
136 			case 2: /* 16V */
137 				m_sound_signal = (m_vcount & 0x10) ? m_decay[m_volume] : 0;
138 				break;
139 			case 3: /* 32V */
140 				m_sound_signal = (m_vcount & 0x20) ? m_decay[m_volume] : 0;
141 				break;
142 			case 4: /* TONE1 */
143 				m_sound_signal = !(m_vcount & 0x01) && !(m_vcount & 0x10) ? m_decay[m_volume] : 0;
144 				break;
145 			case 5: /* TONE2 */
146 				m_sound_signal = !(m_vcount & 0x02) && !(m_vcount & 0x20) ? m_decay[m_volume] : 0;
147 				break;
148 			case 6: /* TONE3 */
149 				m_sound_signal = !(m_vcount & 0x04) && !(m_vcount & 0x40) ? m_decay[m_volume] : 0;
150 				break;
151 			default: /* NOISE */
152 				/* QH of 74164 #4V */
153 				m_sound_signal = (m_noise & 0x8000) ? m_decay[m_volume] : 0;
154 			}
155 
156 		}
157 	}
158 }
159