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