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