1 // license:BSD-3-Clause
2 // copyright-holders:Philip Bennett
3 /***************************************************************************
4 
5     Turret Tower sound hardware
6 
7 ****************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/turrett.h"
11 
12 DEFINE_DEVICE_TYPE(TURRETT, turrett_device, "ttsnd", "Turret Tower Sound")
13 
14 
15 //-------------------------------------------------
16 //  turrett_device - constructor
17 //-------------------------------------------------
18 
turrett_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)19 turrett_device::turrett_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
20 	: device_t(mconfig, TURRETT, tag, owner, clock)
21 	, device_sound_interface(mconfig, *this)
22 	, device_memory_interface(mconfig, *this)
23 	, m_space_config("ttsound", ENDIANNESS_LITTLE, 16, 28, 0)
24 {
25 }
26 
27 
28 //-------------------------------------------------
29 //  memory_space_config - configure address space
30 //-------------------------------------------------
31 
memory_space_config() const32 device_memory_interface::space_config_vector turrett_device::memory_space_config() const
33 {
34 	return space_config_vector {
35 		std::make_pair(0, &m_space_config)
36 	};
37 }
38 
39 
40 //-------------------------------------------------
41 //  device_start - initialize the device
42 //-------------------------------------------------
43 
device_start()44 void turrett_device::device_start()
45 {
46 	// Find our direct access
47 	space().cache(m_cache);
48 
49 	// Create the sound stream
50 	m_stream = stream_alloc(0, 2, 44100);
51 
52 	// Create the volume table
53 	for (int i = 0; i < 0x4f; ++i)
54 		m_volume_table[i] = 65536 * powf(2.0, (-0.375/4) * i);
55 
56 	// Last entry is effectively mute
57 	m_volume_table[0x4f] = 0;
58 
59 	// Register state for saving
60 	for (int ch = 0; ch < SOUND_CHANNELS; ++ch)
61 	{
62 		save_item(NAME(m_channels[ch].m_address), ch);
63 		save_item(NAME(m_channels[ch].m_volume), ch);
64 		save_item(NAME(m_channels[ch].m_playing), ch);
65 	}
66 }
67 
68 
69 //-------------------------------------------------
70 //  device_reset - reset the device
71 //-------------------------------------------------
72 
device_reset()73 void turrett_device::device_reset()
74 {
75 	for (auto & elem : m_channels)
76 		elem.m_playing = false;
77 }
78 
79 
80 //-------------------------------------------------
81 //  sound_stream_update - update sound stream
82 //-------------------------------------------------
83 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)84 void turrett_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
85 {
86 	// Silence the buffers
87 	outputs[0].fill(0);
88 	outputs[1].fill(0);
89 
90 	for (int ch = 0; ch < SOUND_CHANNELS; ++ch)
91 	{
92 		if (m_channels[ch].m_playing)
93 		{
94 			uint32_t &addr = m_channels[ch].m_address;
95 			int32_t lvol = (m_channels[ch].m_volume >> 16) & 0xff;
96 			int32_t rvol = m_channels[ch].m_volume & 0xff;
97 
98 			lvol = m_volume_table[lvol];
99 			rvol = m_volume_table[rvol];
100 
101 			// Channels 30 and 31 expect interleaved stereo samples
102 			uint32_t incr = (ch >= 30) ? 2 : 1;
103 
104 			for (int s = 0; s < outputs[0].samples(); ++s)
105 			{
106 				int16_t sample = m_cache.read_word(addr << 1);
107 
108 				if ((uint16_t)sample == 0x8000)
109 				{
110 					m_channels[ch].m_playing = false;
111 					break;
112 				}
113 
114 				addr += incr;
115 
116 				outputs[0].add_int(s, (sample * lvol) >> 17, 32768);
117 				outputs[1].add_int(s, (sample * rvol) >> 17, 32768);
118 			}
119 		}
120 	}
121 }
122 
123 
124 //-------------------------------------------------
125 //  read - host CPU read access
126 //-------------------------------------------------
127 
read(offs_t offset)128 uint32_t turrett_device::read(offs_t offset)
129 {
130 	m_stream->update();
131 
132 	int ch = offset & 0x3f;
133 
134 	return m_channels[ch].m_playing << 31;
135 }
136 
137 
138 //-------------------------------------------------
139 //  write - host CPU write access
140 //-------------------------------------------------
141 
write(offs_t offset,uint32_t data)142 void turrett_device::write(offs_t offset, uint32_t data)
143 {
144 	m_stream->update();
145 
146 	int ch = offset & 0x3f;
147 
148 	if (offset < 0x100/4)
149 	{
150 		if (data == 0)
151 		{
152 			m_channels[ch].m_playing = false;
153 		}
154 		else
155 		{
156 			m_channels[ch].m_address = data;
157 			m_channels[ch].m_playing = true;
158 		}
159 	}
160 	else
161 	{
162 		m_channels[ch].m_volume = data;
163 	}
164 }
165