1 /*
2 GI SP0250 digital LPC sound synthesizer
3
4 By O. Galibert.
5
6 Unknown:
7 - Exact noise algorithm
8 - Exact noise pitch (probably ok)
9 - Exact main frequency (probably ok)
10 - Exact amplitude decoding (aka mantissa:exponent)
11 - 7 bits output mapping
12 - Whether the pitch starts counting from 0 or 1
13
14 Sound quite reasonably already though.
15 */
16
17 #include <math.h>
18 #include "driver.h"
19 #include "cpuintrf.h"
20
21 enum { MAIN_CLOCK = 10000 };
22
23 static struct {
24 INT16 amp;
25 UINT8 pitch;
26 UINT8 repeat;
27 UINT8 pcount, rcount;
28 UINT8 pcounto, rcounto;
29 UINT32 RNG;
30 int stream;
31 int voiced;
32 UINT8 fifo[15];
33 int fifo_pos;
34
35 void (*drq)(int state);
36
37 struct {
38 INT16 F, B;
39 INT16 z1, z2;
40 } filter[6];
41 } sp0250;
42
43 // Internal ROM to the chip, cf. manual
44
45 static UINT16 coefs[128] = {
46 0, 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 113, 121,
47 129, 137, 145, 153, 161, 169, 177, 185, 193, 201, 203, 217, 225, 233, 241, 249,
48 257, 265, 273, 281, 289, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337,
49 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401,
50 405, 409, 413, 417, 421, 425, 427, 429, 431, 433, 435, 437, 439, 441, 443, 445,
51 447, 449, 451, 453, 455, 457, 459, 461, 463, 465, 467, 469, 471, 473, 475, 477,
52 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495,
53 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511
54 };
55
56 // To be checked, somehow
57
sp0250_ga(UINT8 v)58 static UINT16 sp0250_ga(UINT8 v)
59 {
60 return (v & 0x1f) << (v>>5);
61 }
62
sp0250_gc(UINT8 v)63 static INT16 sp0250_gc(UINT8 v)
64 {
65 INT16 res = coefs[v & 0x7f];
66 if(!(v & 0x80))
67 res = -res;
68 return res;
69 }
70
sp0250_load_values(void)71 static void sp0250_load_values(void)
72 {
73 sp0250.filter[0].B = sp0250_gc(sp0250.fifo[ 0]);
74 sp0250.filter[0].F = sp0250_gc(sp0250.fifo[ 1]);
75 sp0250.amp = sp0250_ga(sp0250.fifo[ 2]);
76 sp0250.filter[1].B = sp0250_gc(sp0250.fifo[ 3]);
77 sp0250.filter[1].F = sp0250_gc(sp0250.fifo[ 4]);
78 sp0250.pitch = sp0250.fifo[ 5];
79 sp0250.filter[2].B = sp0250_gc(sp0250.fifo[ 6]);
80 sp0250.filter[2].F = sp0250_gc(sp0250.fifo[ 7]);
81 sp0250.repeat = sp0250.fifo[ 8] & 0x3f;
82 sp0250.voiced = sp0250.fifo[ 8] & 0x40;
83 sp0250.filter[3].B = sp0250_gc(sp0250.fifo[ 9]);
84 sp0250.filter[3].F = sp0250_gc(sp0250.fifo[10]);
85 sp0250.filter[4].B = sp0250_gc(sp0250.fifo[11]);
86 sp0250.filter[4].F = sp0250_gc(sp0250.fifo[12]);
87 sp0250.filter[5].B = sp0250_gc(sp0250.fifo[13]);
88 sp0250.filter[5].F = sp0250_gc(sp0250.fifo[14]);
89 sp0250.fifo_pos = 0;
90 sp0250.drq(ASSERT_LINE);
91 }
92
sp0250_timer_tick(int param)93 static void sp0250_timer_tick(int param)
94 {
95 sp0250.pcount++;
96 if(sp0250.pcount >= sp0250.pitch) {
97 sp0250.pcount = 0;
98 sp0250.rcount++;
99 if(sp0250.rcount >= sp0250.repeat) {
100 sp0250.rcount = 0;
101 stream_update(sp0250.stream, 0);
102
103 // The synchronisation between the update callback and the
104 // timer tick is crap. Specifically, the timer tick goes
105 // a little faster. So compensate.
106
107 sp0250.pcount = sp0250.pcounto;
108 sp0250.rcount = sp0250.rcounto;
109 if(sp0250.pcount || sp0250.rcount)
110 return;
111
112 if(sp0250.fifo_pos == 15)
113 sp0250_load_values();
114 else {
115 sp0250.amp = 0;
116 sp0250.pitch = 0;
117 sp0250.repeat = 0;
118 }
119 }
120 }
121 }
122
sp0250_update(int num,INT16 * output,int length)123 static void sp0250_update(int num, INT16 *output, int length)
124 {
125 int i;
126 for(i=0; i<length; i++) {
127 INT16 z0 = 0;
128 int f;
129
130 if(sp0250.voiced)
131 if(!sp0250.pcounto)
132 z0 = sp0250.amp;
133 else
134 z0 = 0;
135 else {
136 // Borrowing the ay noise generation LFSR
137
138 if(sp0250.RNG & 1) {
139 z0 = sp0250.amp;
140 sp0250.RNG ^= 0x24000;
141 } else
142 z0 = -sp0250.amp;
143 sp0250.RNG >>= 1;
144 }
145 for(f=0; f<6; f++) {
146 z0 += ((sp0250.filter[f].z1 * sp0250.filter[f].F) >> 8)
147 + ((sp0250.filter[f].z2 * sp0250.filter[f].B) >> 9);
148 sp0250.filter[f].z2 = sp0250.filter[f].z1;
149 sp0250.filter[f].z1 = z0;
150 }
151
152 // Physical resolution is only 7 bits, but heh
153 output[i] = z0;
154
155 sp0250.pcounto++;
156 if(sp0250.pcounto >= sp0250.pitch) {
157 sp0250.pcounto = 0;
158 sp0250.rcounto++;
159 if(sp0250.rcounto >= sp0250.repeat)
160 sp0250.rcounto = 0;
161 }
162 }
163 }
164
165
sp0250_sh_start(const struct MachineSound * msound)166 int sp0250_sh_start( const struct MachineSound *msound )
167 {
168 struct sp0250_interface *intf = msound->sound_interface;
169 memset(&sp0250, 0, sizeof(sp0250));
170 sp0250.RNG = 1;
171 sp0250.drq = intf->drq_callback;
172 sp0250.drq(ASSERT_LINE);
173 timer_pulse(TIME_IN_HZ(MAIN_CLOCK), 0, sp0250_timer_tick);
174
175 sp0250.stream = stream_init("SP0250", intf->volume, MAIN_CLOCK, 0, sp0250_update);
176
177 return 0;
178 }
179
sp0250_sh_stop(void)180 void sp0250_sh_stop( void )
181 {
182 }
183
184
WRITE_HANDLER(sp0250_w)185 WRITE_HANDLER( sp0250_w )
186 {
187 if(sp0250.fifo_pos != 15) {
188 sp0250.fifo[sp0250.fifo_pos++] = data;
189 if(sp0250.fifo_pos == 15)
190 sp0250.drq(CLEAR_LINE);
191 }
192 }
193