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