1 // license:GPL-2.0+
2 // copyright-holders:Juergen Buchmueller, Frank Palazzolo, Sean Riddle
3 #include "emu.h"
4 #include "audio/channelf.h"
5
6
7 #define MAX_AMPLITUDE 0x7fff
8
9 DEFINE_DEVICE_TYPE(CHANNELF_SOUND, channelf_sound_device, "channelf_sound", "Channel F Sound")
10
channelf_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)11 channelf_sound_device::channelf_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
12 : device_t(mconfig, CHANNELF_SOUND, tag, owner, clock),
13 device_sound_interface(mconfig, *this),
14 m_channel(nullptr),
15 m_sound_mode(0),
16 m_incr(0),
17 m_decay_mult(0),
18 m_envelope(0),
19 m_sample_counter(0),
20 m_forced_ontime(0),
21 m_min_ontime(0)
22 {
23 }
24
25 //-------------------------------------------------
26 // device_start - device-specific startup
27 //-------------------------------------------------
28
device_start()29 void channelf_sound_device::device_start()
30 {
31 int rate;
32
33 m_channel = stream_alloc(0, 1, machine().sample_rate());
34 rate = machine().sample_rate();
35
36 /*
37 * 2V = 1000Hz ~= 3579535/224/16
38 * Note 2V on the schematic is not the 2V scanline counter -
39 * it is the 2V vertical pixel counter
40 * 1 pixel = 4 scanlines high
41 *
42 *
43 * This is a convenient way to generate the relevant frequencies,
44 * using a DDS (Direct Digital Synthesizer)
45 *
46 * Essentially, you want a counter to overflow some bit position
47 * at a fixed rate. So, you figure out a number which you can add
48 * to the counter at every sample, so that you will achieve this
49 *
50 * In this case, we want to overflow bit 16 and the 2V rate, 1000Hz.
51 * This means we also get bit 17 = 4V, bit 18 = 8V, etc.
52 */
53
54 /* This is the proper value to add per sample */
55 m_incr = 65536.0/(rate/1000.0/2.0);
56
57 // added for improved sound
58 /* This is the minimum forced ontime, in samples */
59 m_min_ontime = rate/1000*2; /* approx 2ms - estimated, not verified on HW */
60
61 /* This was measured, decay envelope with half life of ~9ms */
62 /* (this is decay multiplier per sample) */
63 m_decay_mult = exp((-0.693/9e-3)/rate);
64
65 /* initial conditions */
66 m_envelope = 0;
67 }
68
69 //-------------------------------------------------
70 // sound_stream_update - handle a stream update
71 //-------------------------------------------------
72
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)73 void channelf_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
74 {
75 uint32_t mask = 0, target = 0;
76 auto &buffer = outputs[0];
77
78 switch( m_sound_mode )
79 {
80 case 0: /* sound off */
81 buffer.fill(0);
82 return;
83
84 case 1: /* high tone (2V) - 1000Hz */
85 mask = 0x00010000;
86 target = 0x00010000;
87 break;
88 case 2: /* medium tone (4V) - 500Hz */
89 mask = 0x00020000;
90 target = 0x00020000;
91 break;
92 case 3: /* low (weird) tone (32V & 8V) */
93 mask = 0x00140000;
94 target = 0x00140000;
95 break;
96 }
97
98 for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
99 {
100 if ((m_forced_ontime > 0) || ((m_sample_counter & mask) == target)) // change made for improved sound
101 buffer.put_int(sampindex, m_envelope, 32768);
102 else
103 buffer.put(sampindex, 0);
104 m_sample_counter += m_incr;
105 m_envelope *= m_decay_mult;
106 if (m_forced_ontime > 0) // added for improved sound
107 m_forced_ontime -= 1; // added for improved sound
108 }
109 }
110
sound_w(int mode)111 void channelf_sound_device::sound_w(int mode)
112 {
113 if (mode == m_sound_mode)
114 return;
115
116 m_channel->update();
117 m_sound_mode = mode;
118
119 switch(mode)
120 {
121 case 0:
122 m_envelope = 0;
123 m_forced_ontime = 0; // added for improved sound
124 break;
125 case 1:
126 case 2:
127 case 3:
128 m_envelope = MAX_AMPLITUDE;
129 m_forced_ontime = m_min_ontime; // added for improved sound
130 break;
131 }
132 }
133