1 /****************************************************************************
2  *
3  * geebee.c
4  *
5  * sound driver
6  * juergen buchmueller <pullmoll@t-online.de>, jan 2000
7  *
8  ****************************************************************************/
9 
10 #include <math.h>
11 #include "driver.h"
12 
13 static void *volume_timer = NULL;
14 static UINT16 *decay = NULL;
15 static int channel;
16 static int sound_latch = 0;
17 static int sound_signal = 0;
18 static int volume = 0;
19 static int noise = 0;
20 
volume_decay(int param)21 static void volume_decay(int param)
22 {
23 	if( --volume < 0 )
24 		volume = 0;
25 }
26 
WRITE_HANDLER(geebee_sound_w)27 WRITE_HANDLER( geebee_sound_w )
28 {
29 	stream_update(channel,0);
30 	sound_latch = data;
31 	volume = 0x7fff; /* set volume */
32 	noise = 0x0000;  /* reset noise shifter */
33 	/* faster decay enabled? */
34 	if( sound_latch & 8 )
35 	{
36 		/*
37 		 * R24 is 10k, Rb is 0, C57 is 1uF
38 		 * charge time t1 = 0.693 * (R24 + Rb) * C57 -> 0.22176s
39 		 * discharge time t2 = 0.693 * (Rb) * C57 -> 0
40 		 * Then C33 is only charged via D6 (1N914), not discharged!
41 		 * Decay:
42 		 * discharge C33 (1uF) through R50 (22k) -> 0.14058s
43 		 */
44 		if( volume_timer )
45 			timer_remove(volume_timer);
46 		volume_timer = timer_pulse(TIME_IN_HZ(32768/0.14058), 0, volume_decay);
47 	}
48 	else
49 	{
50 		/*
51 		 * discharge only after R49 (100k) in the amplifier section,
52 		 * so the volume shouldn't very fast and only when the signal
53 		 * is gated through 6N (4066).
54 		 * I can only guess here that the decay should be slower,
55 		 * maybe half as fast?
56 		 */
57 		if( volume_timer )
58 			timer_remove(volume_timer);
59 		volume_timer = timer_pulse(TIME_IN_HZ(32768/0.2906), 0, volume_decay);
60     }
61 }
62 
geebee_sound_update(int param,INT16 * buffer,int length)63 static void geebee_sound_update(int param, INT16 *buffer, int length)
64 {
65     static int vcarry = 0;
66     static int vcount = 0;
67 
68     while (length--)
69     {
70 		*buffer++ = sound_signal;
71 		/* 1V = HSYNC = 18.432MHz / 3 / 2 / 384 = 8000Hz */
72 		vcarry -= 18432000 / 3 / 2 / 384;
73         while (vcarry < 0)
74         {
75             vcarry += Machine->sample_rate;
76             vcount++;
77 			/* noise clocked with raising edge of 2V */
78 			if ((vcount & 3) == 2)
79 			{
80 				/* bit0 = bit0 ^ !bit10 */
81 				if ((noise & 1) == ((noise >> 10) & 1))
82 					noise = ((noise << 1) & 0xfffe) | 1;
83 				else
84 					noise = (noise << 1) & 0xfffe;
85 			}
86             switch (sound_latch & 7)
87             {
88             case 0: /* 4V */
89 				sound_signal = (vcount & 0x04) ? decay[volume] : 0;
90                 break;
91             case 1: /* 8V */
92 				sound_signal = (vcount & 0x08) ? decay[volume] : 0;
93                 break;
94             case 2: /* 16V */
95 				sound_signal = (vcount & 0x10) ? decay[volume] : 0;
96                 break;
97             case 3: /* 32V */
98 				sound_signal = (vcount & 0x20) ? decay[volume] : 0;
99                 break;
100             case 4: /* TONE1 */
101 				sound_signal = !(vcount & 0x01) && !(vcount & 0x10) ? decay[volume] : 0;
102                 break;
103             case 5: /* TONE2 */
104 				sound_signal = !(vcount & 0x02) && !(vcount & 0x20) ? decay[volume] : 0;
105                 break;
106             case 6: /* TONE3 */
107 				sound_signal = !(vcount & 0x04) && !(vcount & 0x40) ? decay[volume] : 0;
108                 break;
109 			default: /* NOISE */
110 				/* QH of 74164 #4V */
111                 sound_signal = (noise & 0x8000) ? decay[volume] : 0;
112             }
113         }
114     }
115 }
116 
geebee_sh_start(const struct MachineSound * msound)117 int geebee_sh_start(const struct MachineSound *msound)
118 {
119 	int i;
120 
121 	decay = (UINT16 *)malloc(32768 * sizeof(INT16));
122 	if( !decay )
123 		return 1;
124 
125     for( i = 0; i < 0x8000; i++ )
126 		decay[0x7fff-i] = (INT16) (0x7fff/exp(1.0*i/4096));
127 
128 	channel = stream_init("GeeBee", 100, Machine->sample_rate, 0, geebee_sound_update);
129     return 0;
130 }
131 
geebee_sh_stop(void)132 void geebee_sh_stop(void)
133 {
134 	if( volume_timer )
135 		timer_remove(volume_timer);
136 	volume_timer = NULL;
137     if( decay )
138 		free(decay);
139 	decay = NULL;
140 }
141 
geebee_sh_update(void)142 void geebee_sh_update(void)
143 {
144 	stream_update(channel,0);
145 }
146