1 /* aNetHack 0.0.1 sound.c $ANH-Date: 1432512792 2015/05/25 00:13:12 $ $ANH-Branch: master $:$ANH-Revision: 1.8 $ */
2 /* Copyright (c) aNetHack PC Development Team 1993,1995 */
3 /* aNetHack 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
)
32 iflags
.usepcspeaker
= 0;
35 if (strncmpi(sopt
, "def", 3) == 0) { /* default */
36 /* do nothing - default */
39 else if (strncmpi(sopt
, "speaker", 7) == 0) { /* pc speaker */
40 iflags
.usepcspeaker
= 1;
43 else if (strncmpi(sopt
, "auto", 4) == 0) { /* autodetect */
45 * Auto-detect Priorities (arbitrary for now):
52 iflags
.usepcspeaker
= 1;
63 /* 8254/3 Control Word Defines */
65 #define CTR0SEL (0 << 6)
66 #define CTR1SEL (1 << 6)
67 #define CTR2SEL (2 << 6)
68 #define RDBACK (3 << 6)
70 #define LATCH (0 << 4)
71 #define RW_LSB (1 << 4)
72 #define RW_MSB (2 << 4) /* If both LSB and MSB are read, LSB is done first \
75 #define MODE0 (0 << 1) /* Interrupt on terminal count */
76 #define MODE1 (1 << 1) /* Hardware One-Shot */
77 #define MODE2 (2 << 1) /* Pulse Generator */
78 #define MODE3 (3 << 1) /* Square Wave Generator */
79 #define MODE4 (4 << 1) /* Software Triggered Strobe */
80 #define MODE5 (5 << 1) /* Hardware Triggered Strobe */
82 #define BINARY (0 << 0) /* Binary counter (16 bits) */
83 #define BCD (1 << 0) /* Binary Coded Decimal (BCD) Counter (4 Decades) */
85 /* Misc 8254/3 Defines */
87 #define TIMRFRQ (1193180UL) /* Input frequency to the clock (Hz) */
91 #define TIMER (1 << 0) /* Timer 2 Output connected to Speaker */
92 #define SPKR_ON (1 << 1) /* Turn on/off Speaker */
94 /* Port Definitions */
108 startsound(unsigned freq
)
110 /* To start a sound on the PC:
112 * First, set the second counter to have the correct frequency:
120 count
= TIMRFRQ
/ freq
; /* Divide frequencies to get count. */
123 printf("freq = %u, count = %u\n", freq
, count
);
126 outportb(CTRL
, CTR2SEL
| RW_LSB
| RW_MSB
| MODE3
| BINARY
);
127 outportb(CTR2
, count
& 0x0FF);
128 outportb(CTR2
, count
/ 0x100);
130 /* Next, turn on the speaker */
132 outportb(SPEAKER
, inportb(SPEAKER
) | TIMER
| SPKR_ON
);
138 outportb(SPEAKER
, inportb(SPEAKER
) & ~(TIMER
| SPKR_ON
));
141 static unsigned tempo
, length
, octave
, mtype
;
143 /* The important numbers here are 287700UL for the factors and 4050816000UL
144 * which gives the 440 Hz for the A below middle C. "middle C" is assumed to
145 * be the C at octave 3. The rest are computed by multiplication/division of
146 * 2^(1/12) which came out to 1.05946 on my calculator. It is assumed that
147 * no one will request an octave beyond 6 or below 0. (At octave 7, some
148 * notes still come out ok, but by the end of the octave, the "notes" that
149 * are produced are just ticks.
151 * These numbers were chosen by a process based on the C64 tables (which
152 * weren't standardized) and then were 'standardized' by giving them the
153 * closest value. That's why they don't seem to be based on any sensible
157 unsigned long notefactors
[12] = { 483852, 456695, 431063, 406869,
158 384033, 362479, 342135, 322932,
159 304808, 287700, 271553, 256312 };
164 startsound((unsigned) (4050816000UL / notefactors
[notenum
% 12]
165 >> (7 - notenum
/ 12)));
168 int notes
[7] = { 9, 11, 0, 2, 4, 5, 7 };
175 n
= notes
[toupper(*c
++) - 'A'] + octave
* 12;
176 if (*c
== '#' || *c
== '+') {
179 } else if (*c
== '-') {
191 delaytime(unsigned time
)
193 /* time and twait are in units of milliseconds */
197 switch (toupper(mtype
)) {
209 msleep(time
- twait
);
220 time
= time
* 10 + (*c
++ - '0');
225 time
= (unsigned) (240000 / time
/ tempo
);
240 tempo
= 120, length
= 4, octave
= 3, mtype
= 'N';
249 for (c
= tune
; *c
;) {
250 sscanf(c
+ 1, "%u", &num
);
251 for (n
= c
+ 1; isdigit(*n
); n
++) /* do nothing */
256 switch (toupper(*c
)) {
269 case 'M': c
++; mtype
= *c
; c
++; break;
271 if (num
) tempo
= num
;
272 else printf ("Zero Tempo (%s)!\n", c
);
276 if (num
) length
= num
;
277 else printf ("Zero Length (%s)!\n", c
);
287 delaytime ((240000/length
/tempo
));
290 case '>': if (octave
< 7) octave
++; c
++; break;
291 case '<': if (octave
) octave
--; c
++; break;
297 printf("Unrecognized play value (%s)!\n", c
);
305 pc_speaker(struct obj
*instr
, char *tune
)
307 if (!iflags
.usepcspeaker
)
310 switch (instr
->otyp
) {
313 octave
= 5; /* up one octave */
318 octave
= 2; /* drop two octaves */
325 mtype
= 'L'; /* fast, legato */
339 printf("1) flute\n2) horn\n3) harp\n4) other\n");
341 sscanf(s
, "%d", &tool
);
356 printf("Enter tune:");