1 // license:GPL-2.0+
2 // copyright-holders:David Viens, Peter Trauner
3 /***************************************************************************
4 
5   PeT mess@utanet.at
6   main part in video/
7 
8   Refined with recording/analysis on MPT-03 (PAL UVI chip) by plgDavid
9 
10   NTSC UVI sound clock: 15734Hz (arcadia)
11   PAL  UVI sound clock: 15625Hz (Soundic MPT-03 - owned by plgDavid)
12 ***************************************************************************/
13 
14 
15 #include "emu.h"
16 #include "includes/arcadia.h"
17 
18 //known UVI audio clocks
19 #define UVI_NTSC 15734
20 #define UVI_PAL  15625
21 
22 /* we need to create pulse transitions that sound 'decent'
23    with the current mess/mame interp scheme
24 
25   this is not needed anymore with the new trick in streams.c
26 */
27 
28 #define OSAMP  1
29 
30 //lfsr is 9 bits long (and same as Atari TIA pure noise)
31 #define LFSR_MASK (1<<8)
32 
33 //makes alien invaders samples noise sync.
34 #define LFSR_INIT 0x00f0
35 
36 //lfsr states at resynch borders
37 //0x01c1
38 //0x01e0
39 //0x00f0  //good synch
40 //0x0178
41 //0x01bc
42 
43 
44 // device type definition
45 DEFINE_DEVICE_TYPE(ARCADIA_SOUND, arcadia_sound_device, "arcadia_sound", "Arcadia Custom Sound")
46 
47 //-------------------------------------------------
48 //  arcadia_sound_device - constructor
49 //-------------------------------------------------
50 
arcadia_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)51 arcadia_sound_device::arcadia_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
52 	: device_t(mconfig, ARCADIA_SOUND, tag, owner, clock)
53 	, device_sound_interface(mconfig, *this)
54 {
55 }
56 
57 //-------------------------------------------------
58 //  device_start - device-specific startup
59 //-------------------------------------------------
device_start()60 void arcadia_sound_device::device_start()
61 {
62 	m_channel = stream_alloc(0, 1, UVI_PAL*OSAMP);
63 	m_lfsr    = LFSR_INIT;
64 	m_tval    = 1;
65 	logerror("arcadia_sound start\n");
66 }
67 
68 //-------------------------------------------------
69 //  device_start - device-specific reset
70 //-------------------------------------------------
device_reset()71 void arcadia_sound_device::device_reset()
72 {
73 	memset(m_reg, 0, sizeof(m_reg));
74 	m_omode = 0;
75 	m_pos = 0;
76 }
77 
78 //-------------------------------------------------
79 //  sound_stream_update - handle update requests for
80 //  our sound stream
81 //-------------------------------------------------
82 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)83 void arcadia_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
84 {
85 	int i;
86 	auto &buffer = outputs[0];
87 
88 	for (i = 0; i < buffer.samples(); i++)
89 	{
90 		s32 result = 0;
91 
92 		//if minimal pitch ?
93 		if (m_reg[1]){
94 			switch (m_mode){
95 				//dont play anything
96 				case 0:break;
97 
98 				//tone only
99 				case 1:
100 					result = m_volume * m_tval;
101 				break;
102 
103 				//noise only
104 				case 2:
105 					result = m_volume * m_nval;
106 				break;
107 
108 				//tone AND noise (bitwise and)
109 				case 3:
110 					result = m_volume * (m_tval & m_nval);
111 				break;
112 			}
113 
114 			//counter
115 			m_pos++;
116 
117 			if (m_pos >= m_size){
118 				//calculate new noise bit ( taps: 0000T000T)
119 				unsigned char newBit = m_lfsr & 1;         //first tap
120 				newBit = (newBit ^ ((m_lfsr & 0x10)?1:0) );//xor with second tap
121 
122 				m_nval = m_lfsr & 1; //taking new output from LSB
123 				m_lfsr = m_lfsr >> 1;//shifting
124 
125 				//insert new bit at end position (size-1) (only if non null)
126 				if (newBit)
127 					m_lfsr |= LFSR_MASK;
128 
129 				//invert tone
130 				m_tval = !m_tval;
131 
132 				m_pos = 0;
133 			}
134 		}
135 		buffer.put_int(i, result, 32768);
136 	}
137 }
138 
139 
140 
141 //-------------------------------------------------
142 //  soundport_w
143 //-------------------------------------------------
144 
write(offs_t offset,uint8_t data)145 void arcadia_sound_device::write(offs_t offset, uint8_t data)
146 {
147 	m_channel->update();
148 	m_reg[offset] = data;
149 
150 	//logerror("arcadia_sound write:%x=%x\n",offset,data);
151 
152 	switch (offset)
153 	{
154 		case 1:
155 			//as per Gobbler samples:
156 			//the freq counter is only applied on the next change in the flip flop
157 			m_size = (data & 0x7f)*OSAMP;
158 			//logerror("arcadia_sound write: frq:%d\n",data);
159 
160 			//reset LFSR
161 			if(!m_size)
162 				m_lfsr = LFSR_INIT;
163 		break;
164 
165 		case 2:
166 			m_volume = (data & 0x07) * 0x800;
167 			m_mode   = (data & 0x18) >> 3;
168 
169 			//logerror("arcadia_sound write: vol:%d mode:%d\n",m_volume,m_mode );
170 
171 			if (m_mode != m_omode){
172 				//not 100% sure about this, maybe we should not reset anything
173 				//m_pos  = 0;
174 				m_tval = 0;
175 			}
176 			m_omode = m_mode;
177 		break;
178 	}
179 }
180