|
|
1.1 root 1: /*-----------------------------------------------------------------------------
2: Talking BIOS device driver for the AT&T PC6300.
3: Copyright (C) Karl Dahlke 1987
4: This software may be freely used and distributed
5: for any non-profit purpose.
6: *-----------------------------------------------------------------------------
7: */
8:
9: /* noises.c: generate sounds */
10:
11: #ifndef MSDOS
12: #include <sys/io.h>
13: #endif
14: #include "speech.h"
15:
16: /* intervals, measured in ticks of the timer */
17: #define TICKS_CYCLE 11932
18: #define TICKS_CLICK 1000
19: #define TICKS_CHARWAIT 7200
20: #define TICKS_TOPCR 560
21: #define TICKS_BOTCR 64
22: #define TICKS_INCCR 5
23:
24: #define DRAINTICKS 770 /* how long till the squawker's internal buffer is drained */
25:
26: #define SF_LEN 32 /* length of sound fifo */
27:
28: long lbolt;
29: extern int mmticks;
30:
31: /* sound control variables, console only */
32: int sdnoises = 1, sdtones = 0;
33:
34: static short sf_fifo[SF_LEN];
35: static int sf_head, sf_tail;
36: static long wait_lbolt;
37:
38: static freqset(freq)
39: int freq;
40: {
41: short istate;
42: istate = sphi();
43: if(freq < 0) /* turn off tone */
44: outb(0x61, inb(0x61) & ~1);
45: else {
46: outb(0x43, 0xb6);
47: outb(0x42, freq);
48: outb(0x42, (freq>>8));
49: outb(0x61, inb(0x61) | 3);
50: }
51: spl(istate);
52: } /* freqset */
53:
54: static putfifo(p)
55: short *p;
56: {
57: short istate;
58: int i;
59:
60: istate = sphi();
61: i = sf_head;
62: while(*p) {
63: sf_fifo[i++] = *p++;
64: if(i == SF_LEN) i = 0;
65: if(i == sf_tail) goto done;
66: }
67: sf_head = i;
68:
69: done: spl(istate);
70: } /* putfifo */
71:
72: chkfifo()
73: {
74: int i;
75: short freq;
76: long l;
77:
78: if(wait_lbolt) {
79: l = lbolt - wait_lbolt;
80: if(l >= 0 || l <= -1000) {
81: freqset(-1);
82: wait_lbolt = 0;
83: }
84: }
85:
86: if(!wait_lbolt) {
87: if((i = sf_tail) != sf_head) {
88: freq = sf_fifo[i++];
89: if(i == SF_LEN) i = 0;
90: l = sf_fifo[i++];
91: if(i == SF_LEN) i = 0;
92: sf_tail = i;
93: freqset(freq);
94: wait_lbolt = lbolt + l;
95: }
96: }
97:
98: #ifndef MSDOS
99: if(wait_lbolt && mmticks == 10) mmticks = 1; /* higher resolution */
100: #endif
101: } /* chkfifo */
102:
103: /* generate a sound based on the passed parameter */
104: /* should only be called when the session runs on the console */
105: sdsound(sound)
106: {
107: short *snd_array;
108: static short startsnd[] = {2000,10,1500,10,1333,10,1123,10,0,0};
109: static short bellsnd[] = {662,5,0,0};
110: static short boundsnd[] = {376,3,316,3,0,0};
111: static short offsnd[] = {4800,3,0,0};
112: static short onsnd[] = {2000,10,0,0};
113: static short buzzsnd[] = {8000,20,0,0};
114: static short *soundlist[] = {
115: 0, 0, 0, bellsnd, boundsnd, offsnd, onsnd, buzzsnd, startsnd};
116:
117: if(!sdnoises) return;
118:
119: snd_array = soundlist[sound];
120: if(snd_array)
121: putfifo(snd_array);
122: if(sound == 2) crsnd();
123: if(sound == 1) spk_click();
124: } /* sdsound */
125:
126: /* under Coherent, we return an integer that indicates whether
127: * the mmtime() function should take a real time break before processing
128: * this or subsequent characters.
129: * Sometimes the time to wait before creating the click of the next
130: * character extends beyond the next system clock interrupt.
131: * In this case, there is no point in hogging the CPU.
132: * Return 1 to indicate that this character should be held,
133: * and acted upon once the mmtime() function is reinvoked
134: * at the next system clock interrupt, unless of course there
135: * is something else ready to run, such as my wife's word processor
136: * or a cron job.
137: * A return of 0 means we waited the proper amount of time and made the
138: * corresponding noise, and we are ready to receive the next character.
139: * If we are running musical output, the tone must persist for approx
140: * a tenth of a second. Return 2 to indicate this. */
141: int sdcharsnd(c)
142: char c;
143: {
144: /* lr_notes[i] = 1193181/(1000*1.02^(i+1)) */
145: static short lr_notes[] = {
146: 1168,1146,1124,1102,1080,1060,1038,1018,1000,980,960,942,924,906,888,872,
147: 854,838,822,806,790,774,760,744,730,716,702,688,674,662,648,636,
148: 624,612,600,588,576,566,554,544,532,522,512,502,492,482,474,464,
149: 454,446,438,428,420,412,404,396,388,380,374,366,358,352,344,338};
150:
151: /* make sound accompanying this character */
152: if(sdtones) {
153: #ifdef MSDOS
154: while(wait_lbolt || sf_head != sf_tail) ;
155: #endif
156:
157: if(c == 13) sdsound(2);
158: if(c >= 96) c -= 32;
159: freqset(-1);
160: if(c > ' ') freqset(lr_notes[c-' ']);
161: wait_lbolt = lbolt + 5;
162: return 8;
163: } /* sdtones */
164:
165: if(sdnoises) {
166: switch(c) {
167: case 7: sdsound(3); break;
168: case 13: sdsound(2); break;
169: default:
170: if(c > ' ')
171: sdsound(1);
172: #ifdef MSDOS
173: else
174: sdpause(TICKS_CLICK);
175: #endif
176: break;
177: }
178: #ifdef MSDOS
179: sdpause(TICKS_CHARWAIT - TICKS_CLICK);
180: #endif
181: return 4;
182: } /* noises on */
183:
184: return 0;
185: } /* sdcharsnd */
186:
187: /* sound for turning a mode on or off, from within a deferred function */
188: sdonoff(onoff)
189: {
190: if(!sdsession)
191: sdsound(5+onoff);
192: } /* sdonoff */
193:
194: draincheck()
195: {
196: long l;
197:
198: if(sdc->drain_lbolt) {
199: l = lbolt - sdc->drain_lbolt;
200: if(l < 0 && l > -1000)
201: return 1; /* still waiting */
202: sdc->drain_lbolt = 0;
203: }
204:
205: return 0;
206: } /* draincheck */
207:
208: drainset(o)
209: struct SDCONTROL *o;
210: {
211: o->drain_lbolt = lbolt + DRAINTICKS;
212: } /* drainset */
213:
214: /* togle the inbuilt speaker */
215: static spk_toggle()
216: {
217: short istate = sphi();
218: char c;
219: c = inb(0x61);
220: /* cannot interrupt a tone with a click */
221: if(!(c&1))
222: outb(0x61, c^2);
223: spl(istate);
224: } /* spk_toggle */
225:
226: /* pause this many clock ticks */
227: sdpause(nticks)
228: {
229: int t0val = read_t0();
230: int nextval;
231: do {
232: nextval = read_t0();
233: t0val -= nextval;
234: #ifndef MSDOS
235: if(t0val < 0) t0val += TICKS_CYCLE;
236: #endif
237: nticks -= t0val;
238: t0val = nextval;
239: } while(nticks > 0);
240: } /* sdpause */
241:
242: /* the sound of a character click */
243: static spk_click()
244: {
245: spk_toggle();
246: sdpause(TICKS_CLICK);
247: spk_toggle();
248: } /* spk_click */
249:
250: crsnd()
251: {
252: int i, nticks, nextval;
253: int t0val = read_t0();
254:
255: for(i=TICKS_TOPCR; i>TICKS_BOTCR; i-=TICKS_INCCR) {
256: spk_toggle();
257: nticks = i;
258: do {
259: nextval = read_t0();
260: t0val -= nextval;
261: #ifndef MSDOS
262: if(t0val < 0) t0val += TICKS_CYCLE;
263: #endif
264: nticks -= t0val;
265: t0val = nextval;
266: } while(nticks > 0);
267: }
268: } /* crsnd */
269:
270: #ifndef MSDOS
271: /* return nonzero if we need to take a real time break */
272: mmgo1(c)
273: int c;
274: {
275: int rc; /* return value */
276: IO iob;
277:
278: /* set up for mmgo() */
279: iob.io_seg = IOSYS;
280: iob.io_ioc = 1;
281: iob.io.vbase = &c;
282: iob.io_flag = 0;
283:
284: mmticks = 1;
285:
286: rc = sdoutchar(0, c);
287:
288: if(rc & 2) {
289: int c1 = c;
290: c = '\33';
291: mmgo(&iob);
292: c = c1;
293: }
294:
295: if(rc & 1) mmgo(&iob);
296:
297: if(rc & 8) {
298: mmticks = 7;
299: return 1;
300: }
301:
302: if(rc & 4) {
303: mmticks = 1;
304: return 2;
305: }
306:
307: return 0;
308: } /* mmgo1 */
309:
310: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.