1 /* SCCS Id: @(#)sound.c 3.4 1996/02/19 */
2 /* Copyright (c) NetHack PC Development Team 1993,1995 */
3 /* NetHack may be freely redistributed. See license for details. */
6 * sound.c - Hardware sound support
9 * Initial Creation 93/10/01
10 * Added PC Speaker Support for BC compilers 95/06/14
11 * Completed various fixes 96/02/19
27 assign_soundcard(sopt)
33 iflags.usepcspeaker = 0;
36 if (strncmpi(sopt,"def",3) == 0) { /* default */
37 /* do nothing - default */
40 else if (strncmpi(sopt,"speaker",7) == 0) { /* pc speaker */
41 iflags.usepcspeaker = 1;
44 else if (strncmpi(sopt,"auto",4) == 0) { /* autodetect */
46 * Auto-detect Priorities (arbitrary for now):
51 else iflags.usepcspeaker = 1;
63 /* 8254/3 Control Word Defines */
65 #define CTR0SEL (0<<6)
66 #define CTR1SEL (1<<6)
67 #define CTR2SEL (2<<6)
72 #define RW_MSB (2<<4) /* If both LSB and MSB are read, LSB is done first */
74 #define MODE0 (0<<1) /* Interrupt on terminal count */
75 #define MODE1 (1<<1) /* Hardware One-Shot */
76 #define MODE2 (2<<1) /* Pulse Generator */
77 #define MODE3 (3<<1) /* Square Wave Generator */
78 #define MODE4 (4<<1) /* Software Triggered Strobe */
79 #define MODE5 (5<<1) /* Hardware Triggered Strobe */
81 #define BINARY (0<<0) /* Binary counter (16 bits) */
82 #define BCD (1<<0) /* Binary Coded Decimal (BCD) Counter (4 Decades) */
84 /* Misc 8254/3 Defines */
86 #define TIMRFRQ (1193180UL) /* Input frequency to the clock (Hz) */
90 #define TIMER (1<<0) /* Timer 2 Output connected to Speaker */
91 #define SPKR_ON (1<<1) /* Turn on/off Speaker */
93 /* Port Definitions */
107 startsound (unsigned freq)
109 /* To start a sound on the PC:
111 * First, set the second counter to have the correct frequency:
116 if (freq == 0) freq = 523;
118 count = TIMRFRQ / freq; /* Divide frequencies to get count. */
121 printf ("freq = %u, count = %u\n", freq, count);
124 outportb (CTRL, CTR2SEL|RW_LSB|RW_MSB|MODE3|BINARY);
125 outportb (CTR2, count & 0x0FF);
126 outportb (CTR2, count / 0x100);
128 /* Next, turn on the speaker */
130 outportb (SPEAKER, inportb(SPEAKER)|TIMER|SPKR_ON);
136 outportb (SPEAKER, inportb(SPEAKER) & ~(TIMER|SPKR_ON));
139 static unsigned tempo, length, octave, mtype;
141 /* The important numbers here are 287700UL for the factors and 4050816000UL
142 * which gives the 440 Hz for the A below middle C. "middle C" is assumed to
143 * be the C at octave 3. The rest are computed by multiplication/division of
144 * 2^(1/12) which came out to 1.05946 on my calculator. It is assumed that
145 * no one will request an octave beyond 6 or below 0. (At octave 7, some
146 * notes still come out ok, but by the end of the octave, the "notes" that
147 * are produced are just ticks.
149 * These numbers were chosen by a process based on the C64 tables (which
150 * weren't standardized) and then were 'standardized' by giving them the
151 * closest value. That's why they don't seem to be based on any sensible
155 unsigned long notefactors[12] = { 483852, 456695, 431063, 406869, 384033,
156 362479, 342135, 322932, 304808, 287700, 271553, 256312 };
161 startsound ((unsigned) (4050816000UL / notefactors[notenum % 12]
162 >> (7 - notenum / 12)));
165 int notes[7] = { 9, 11, 0, 2, 4, 5, 7 };
172 n = notes[toupper(*c++) - 'A'] + octave * 12;
173 if (*c == '#' || *c == '+') { n++; c++; }
174 else if (*c == '-') { if (n) n--; c++; }
182 delaytime (unsigned time)
184 /* time and twait are in units of milliseconds */
188 switch (toupper (mtype)) {
189 case 'S': twait = time / 4; break;
190 case 'L': twait = 0; break;
191 default: twait = time / 8; break;
194 msleep (time - twait);
204 while (isdigit(*c)) time = time * 10 + (*c++ - '0');
206 if (!time) time = length;
208 time = (unsigned)(240000 / time / tempo);
210 while (*c == '.') { time = time * 3 / 2; c++; }
220 tempo = 120, length = 4, octave = 3, mtype = 'N';
230 for (c = tune; *c; ) {
231 sscanf (c + 1, "%u", &num);
232 for (n = c + 1; isdigit(*n); n++) /* do nothing */;
233 if (isspace(*c)) c++;
234 else switch (toupper(*c)) {
247 case 'M': c++; mtype = *c; c++; break;
249 if (num) tempo = num;
250 else printf ("Zero Tempo (%s)!\n", c);
254 if (num) length = num;
255 else printf ("Zero Length (%s)!\n", c);
265 delaytime ((240000/length/tempo));
268 case '>': if (octave < 7) octave++; c++; break;
269 case '<': if (octave) octave--; c++; break;
271 case ' ': c++; break;
273 printf ("Unrecognized play value (%s)!\n", c);
281 pc_speaker (struct obj *instr, char *tune)
283 if (!iflags.usepcspeaker) return;
289 octave = 5; /* up one octave */
294 octave = 2; /* drop two octaves */
301 mtype = 'L'; /* fast, legato */
315 printf ("1) flute\n2) horn\n3) harp\n4) other\n");
316 fgets (s, 80, stdin);
317 sscanf (s, "%d", &tool);
319 case 1: octave = 5; break;
320 case 2: octave = 2; break;
321 case 3: length = 8; mtype = 'L'; break;
324 printf ("Enter tune:");