1 // license:BSD-3-Clause
2 // copyright-holders:Sandro Ronco
3 /***************************************************************************
4
5 Videotone TVC 32/64 sound emulation
6
7 ***************************************************************************/
8
9 #include "emu.h"
10 #include "tvc.h"
11
12 // device type definition
13 DEFINE_DEVICE_TYPE(TVC_SOUND, tvc_sound_device, "tvc_sound", "TVC 64 Custom Sound")
14
15 //-------------------------------------------------
16 // tvc_sound_device - constructor
17 //-------------------------------------------------
18
tvc_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)19 tvc_sound_device::tvc_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
20 device_t(mconfig, TVC_SOUND, tag, owner, clock),
21 device_sound_interface(mconfig, *this),
22 m_write_sndint(*this)
23 {
24 }
25
26 //-------------------------------------------------
27 // device_start - device-specific startup
28 //-------------------------------------------------
device_start()29 void tvc_sound_device::device_start()
30 {
31 // resolve callbacks
32 m_write_sndint.resolve_safe();
33
34 m_stream = stream_alloc(0, 1, machine().sample_rate());
35 m_sndint_timer = timer_alloc(TIMER_SNDINT);
36 }
37
38 //-------------------------------------------------
39 // device_reset - device-specific reset
40 //-------------------------------------------------
device_reset()41 void tvc_sound_device::device_reset()
42 {
43 m_enabled = 0;
44 m_freq = 0;
45 m_incr = 0;
46 m_signal = 1;
47 m_sndint_timer->reset();
48 }
49
50
51 //-------------------------------------------------
52 // device_timer - handler timer events
53 //-------------------------------------------------
54
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)55 void tvc_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
56 {
57 m_write_sndint(1);
58 }
59
60 //-------------------------------------------------
61 // sound_stream_update - handle update requests for
62 // our sound stream
63 //-------------------------------------------------
64
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)65 void tvc_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
66 {
67 auto &output = outputs[0];
68 int rate = output.sample_rate() / 2;
69 if (m_enabled && m_freq)
70 {
71 for (int sampindex = 0; sampindex < output.samples(); sampindex++)
72 {
73 output.put_int(sampindex, m_signal * m_volume, 32768 / 0x0800);
74 m_incr -= m_freq;
75 while(m_incr < 0)
76 {
77 m_incr += rate;
78 m_signal = -m_signal;
79 }
80 }
81 }
82 else
83 {
84 // fill output with 0 if the sound is disabled
85 output.fill(0);
86 }
87 }
88
89
90
91 //-------------------------------------------------
92 // ports write
93 //-------------------------------------------------
94
write(offs_t offset,uint8_t data)95 void tvc_sound_device::write(offs_t offset, uint8_t data)
96 {
97 m_stream->update();
98
99 m_ports[offset] = data;
100
101 switch(offset)
102 {
103 case 1:
104 m_enabled = BIT(data, 4);
105 // fall through
106
107 case 0:
108 {
109 uint16_t pitch = (m_ports[0] | (m_ports[1]<<8)) & 0x0fff;
110 m_freq = (pitch == 0x0fff) ? 0 : (int)(195312.5 / (4096 - pitch));
111
112 if ((m_ports[1] & 0x20) && m_freq != 0)
113 m_sndint_timer->adjust(attotime::from_hz(m_freq), 0, attotime::from_hz(m_freq));
114 else
115 m_sndint_timer->reset();
116
117 break;
118 }
119
120 case 2:
121 m_volume = (data>>2) & 0x0f;
122 break;
123 }
124 }
125
126
127 //-------------------------------------------------
128 // tvc_sound_device::reset_divider
129 //-------------------------------------------------
130
reset_divider()131 void tvc_sound_device::reset_divider()
132 {
133 m_stream->update();
134
135 m_incr = 0;
136 m_signal = 1;
137
138 if (m_ports[1] & 0x20 && m_freq != 0)
139 m_sndint_timer->adjust(attotime::from_hz(m_freq), 0, attotime::from_hz(m_freq));
140 else
141 m_sndint_timer->reset();
142 }
143