1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /*************************************************************************
4
5 Targ hardware
6
7 *************************************************************************/
8
9 /* Sound channel usage
10 0 = CPU music, Shoot
11 1 = Crash
12 2 = Spectar sound
13 3 = Tone generator
14 */
15
16 #include "emu.h"
17 #include "includes/exidy.h"
18 #include "speaker.h"
19
20
21
22 #define SPECTAR_MAXFREQ 525000
23 #define TARG_MAXFREQ 125000
24
25 static const int16_t sine_wave[32] =
26 {
27 0x0f0f, 0x0f0f, 0x0f0f, 0x0606, 0x0606, 0x0909, 0x0909, 0x0606, 0x0606, 0x0909, 0x0606, 0x0d0d, 0x0f0f, 0x0f0f, 0x0d0d, 0x0000,
28 -0x191a, -0x2122, -0x1e1f, -0x191a, -0x1314, -0x191a, -0x1819, -0x1819, -0x1819, -0x1314, -0x1314, -0x1314, -0x1819, -0x1e1f, -0x1e1f, -0x1819
29 };
30
31
32 /* some macros to make detecting bit changes easier */
33 #define RISING_EDGE(bit) ( (data & bit) && !(m_port_1_last & bit))
34 #define FALLING_EDGE(bit) (!(data & bit) && (m_port_1_last & bit))
35
36
adjust_sample(uint8_t freq)37 void exidy_state::adjust_sample(uint8_t freq)
38 {
39 m_tone_freq = freq;
40
41 if (!m_samples->playing(3))
42 {
43 m_samples->set_volume(3, 0);
44 m_samples->start_raw(3, sine_wave, 32, 1000, true);
45 }
46
47 if ((m_tone_freq == 0xff) || (m_tone_freq == 0x00))
48 m_samples->set_volume(3, 0);
49 else
50 {
51 m_samples->set_frequency(3, 1.0 * m_max_freq / (0xff - m_tone_freq));
52 m_samples->set_volume(3, m_tone_active);
53 }
54 }
55
56
targ_audio_1_w(uint8_t data)57 void exidy_state::targ_audio_1_w(uint8_t data)
58 {
59 /* CPU music */
60 if (BIT(m_port_1_last ^ data, 0))
61 m_dac->write(BIT(data, 0));
62
63 /* shot */
64 if (FALLING_EDGE(0x02) && !m_samples->playing(0)) m_samples->start(0,1);
65 if (RISING_EDGE(0x02)) m_samples->start(0,1);
66
67 /* crash */
68 if (RISING_EDGE(0x20))
69 {
70 if (data & 0x40)
71 m_samples->start(1,0);
72 else
73 m_samples->start(1,2);
74 }
75
76 /* Sspec */
77 if (data & 0x10)
78 m_samples->stop(2);
79 else
80 {
81 if ((data & 0x08) != (m_port_1_last & 0x08))
82 {
83 if (data & 0x08)
84 m_samples->start(2,3,true);
85 else
86 m_samples->start(2,4,true);
87 }
88 }
89
90 /* Game (tone generator enable) */
91 if (FALLING_EDGE(0x80))
92 {
93 m_tone_pointer = 0;
94 m_tone_active = 0;
95
96 adjust_sample(m_tone_freq);
97 }
98
99 if (RISING_EDGE(0x80))
100 m_tone_active=1;
101
102 m_port_1_last = data;
103 }
104
105
targ_audio_2_w(uint8_t data)106 void exidy_state::targ_audio_2_w(uint8_t data)
107 {
108 if ((data & 0x01) && !(m_port_2_last & 0x01))
109 {
110 uint8_t *prom = memregion("targ")->base();
111
112 m_tone_pointer = (m_tone_pointer + 1) & 0x0f;
113
114 adjust_sample(prom[((data & 0x02) << 3) | m_tone_pointer]);
115 }
116
117 m_port_2_last = data;
118 }
119
120
spectar_audio_2_w(uint8_t data)121 void exidy_state::spectar_audio_2_w(uint8_t data)
122 {
123 adjust_sample(data);
124 }
125
126
127 static const char *const sample_names[] =
128 {
129 "*targ",
130 "expl",
131 "shot",
132 "sexpl",
133 "spslow",
134 "spfast",
135 nullptr
136 };
137
138
139
common_audio_start(int freq)140 void exidy_state::common_audio_start(int freq)
141 {
142 m_max_freq = freq;
143
144 m_tone_freq = 0;
145 m_tone_active = 0;
146
147 /* start_raw can't be called here: chan.source will be set by
148 samples_device::device_start and then nulled out by samples_device::device_reset
149 at the soft_reset stage of init_machine() and will never be set again.
150 Thus, I've moved it to exidy_state::adjust_sample() were it will be set after
151 machine initialization. */
152 //m_samples->set_volume(3, 0);
153 //m_samples->start_raw(3, sine_wave, 32, 1000, true);
154
155 save_item(NAME(m_port_1_last));
156 save_item(NAME(m_port_2_last));
157 save_item(NAME(m_tone_freq));
158 save_item(NAME(m_tone_active));
159 }
160
161
SAMPLES_START_CB_MEMBER(exidy_state::spectar_audio_start)162 SAMPLES_START_CB_MEMBER(exidy_state::spectar_audio_start)
163 {
164 common_audio_start(SPECTAR_MAXFREQ);
165 }
166
167
SAMPLES_START_CB_MEMBER(exidy_state::targ_audio_start)168 SAMPLES_START_CB_MEMBER(exidy_state::targ_audio_start)
169 {
170 common_audio_start(TARG_MAXFREQ);
171
172 m_tone_pointer = 0;
173
174 save_item(NAME(m_tone_pointer));
175 }
176
177
spectar_audio(machine_config & config)178 void exidy_state::spectar_audio(machine_config &config)
179 {
180 SPEAKER(config, "speaker").front_center();
181
182 SAMPLES(config, m_samples);
183 m_samples->set_channels(4);
184 m_samples->set_samples_names(sample_names);
185 m_samples->set_samples_start_callback(FUNC(exidy_state::spectar_audio_start));
186 m_samples->add_route(ALL_OUTPUTS, "speaker", 0.25);
187
188 DAC_1BIT(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.99);
189 }
190
targ_audio(machine_config & config)191 void exidy_state::targ_audio(machine_config &config)
192 {
193 SPEAKER(config, "speaker").front_center();
194
195 SAMPLES(config, m_samples);
196 m_samples->set_channels(4);
197 m_samples->set_samples_names(sample_names);
198 m_samples->set_samples_start_callback(FUNC(exidy_state::targ_audio_start));
199 m_samples->add_route(ALL_OUTPUTS, "speaker", 0.25);
200
201 DAC_1BIT(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.99);
202 }
203