]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:05:57 +0000 (21:05 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:05:57 +0000 (21:05 +0000)
sys/msdos/sound.c [new file with mode: 0644]

diff --git a/sys/msdos/sound.c b/sys/msdos/sound.c
new file mode 100644 (file)
index 0000000..847bde2
--- /dev/null
@@ -0,0 +1,332 @@
+/*   SCCS Id: @(#)sound.c   3.3     96/02/19                        */
+/*   Copyright (c) NetHack PC Development Team 1993,1995            */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * sound.c - Hardware sound support
+ *
+ *Edit History:
+ *     Initial Creation                              93/10/01
+ *     Added PC Speaker Support for BC compilers     95/06/14
+ *     Completed various fixes                      96/02/19
+ *
+ */
+
+#include "hack.h"
+#include <stdio.h>
+#include "portio.h"
+
+#include <dos.h>
+#include <ctype.h>
+
+#ifndef TESTING
+
+#define printf pline
+
+int
+assign_soundcard(sopt)
+char *sopt;
+{
+
+       iflags.hassound = 0;
+#  ifdef PCMUSIC
+       iflags.usepcspeaker = 0;
+#  endif
+
+       if (strncmpi(sopt,"def",3) == 0) {              /* default */
+               /* do nothing - default */
+       }
+#  ifdef PCMUSIC
+       else if (strncmpi(sopt,"speaker",7) == 0) {     /* pc speaker */
+               iflags.usepcspeaker = 1;
+       }
+#  endif
+       else if (strncmpi(sopt,"auto",4) == 0) {        /* autodetect */
+       /*
+        * Auto-detect Priorities (arbitrary for now):
+        *      Just pcspeaker
+        */
+               if (0) ;
+#  ifdef PCMUSIC
+               else iflags.usepcspeaker = 1;
+#  endif
+       } else {
+               return 0;
+       }
+       return 1;
+
+}
+#endif
+
+#ifdef PCMUSIC
+
+/* 8254/3 Control Word Defines */
+
+#define CTR0SEL (0<<6)
+#define        CTR1SEL (1<<6)
+#define        CTR2SEL (2<<6)
+#define RDBACK (3<<6)
+
+#define LATCH  (0<<4)
+#define        RW_LSB  (1<<4)
+#define RW_MSB (2<<4)  /* If both LSB and MSB are read, LSB is done first */
+
+#define MODE0  (0<<1)  /* Interrupt on terminal count */
+#define MODE1  (1<<1)  /* Hardware One-Shot */
+#define MODE2  (2<<1)  /* Pulse Generator */
+#define MODE3  (3<<1)  /* Square Wave Generator */
+#define MODE4  (4<<1)  /* Software Triggered Strobe */
+#define MODE5  (5<<1)  /* Hardware Triggered Strobe */
+
+#define BINARY (0<<0)  /* Binary counter (16 bits) */
+#define BCD    (1<<0)  /* Binary Coded Decimal (BCD) Counter (4 Decades) */
+
+/* Misc 8254/3 Defines */
+
+#define TIMRFRQ (1193180UL)    /* Input frequency to the clock (Hz) */
+
+/* Speaker Defines */
+
+#define TIMER  (1<<0)  /* Timer 2 Output connected to Speaker */
+#define SPKR_ON        (1<<1)  /* Turn on/off Speaker */
+
+/* Port Definitions */
+
+/* 8254/3 Ports */
+
+#define CTR0   0x40
+#define CTR1   0x41
+#define CTR2   0x42
+#define CTRL   0x43
+
+/* Speaker Port */
+
+#define SPEAKER        0x61
+
+void
+startsound (unsigned freq)
+{
+       /* To start a sound on the PC:
+        *
+        * First, set the second counter to have the correct frequency:
+        */
+
+       unsigned count;
+
+       if (freq == 0) freq = 523;
+
+       count = TIMRFRQ / freq; /* Divide frequencies to get count. */
+
+#ifdef TESTING
+       printf ("freq = %u, count = %u\n", freq, count);
+#endif
+
+       outportb (CTRL, CTR2SEL|RW_LSB|RW_MSB|MODE3|BINARY);
+       outportb (CTR2, count & 0x0FF);
+       outportb (CTR2, count / 0x100);
+
+       /* Next, turn on the speaker */
+
+        outportb (SPEAKER, inportb(SPEAKER)|TIMER|SPKR_ON);
+}
+
+void
+stopsound (void)
+{
+        outportb (SPEAKER, inportb(SPEAKER) & ~(TIMER|SPKR_ON));
+}
+
+static unsigned tempo, length, octave, mtype;
+
+/* The important numbers here are 287700UL for the factors and 4050816000UL
+ * which gives the 440 Hz for the A below middle C. "middle C" is assumed to
+ * be the C at octave 3. The rest are computed by multiplication/division of
+ * 2^(1/12) which came out to 1.05946 on my calculator.  It is assumed that
+ * no one will request an octave beyond 6 or below 0.  (At octave 7, some
+ * notes still come out ok, but by the end of the octave, the "notes" that
+ * are produced are just ticks.
+
+ * These numbers were chosen by a process based on the C64 tables (which
+ * weren't standardized) and then were 'standardized' by giving them the
+ * closest value.  That's why they don't seem to be based on any sensible
+ * number.
+ */
+
+unsigned long notefactors[12] = { 483852, 456695, 431063, 406869, 384033,
+       362479, 342135, 322932, 304808, 287700, 271553, 256312 };
+
+void
+note (long notenum)
+{
+       startsound ((unsigned) (4050816000UL / notefactors[notenum % 12]
+                          >> (7 - notenum / 12)));
+}
+
+int notes[7] = { 9, 11, 0, 2, 4, 5, 7 };
+
+char *
+startnote (char *c)
+{
+       long n;
+
+       n = notes[toupper(*c++) - 'A'] + octave * 12;
+       if (*c == '#' || *c == '+') { n++; c++; }
+       else if (*c == '-') { if (n) n--; c++; }
+
+       note (n);
+
+       return --c;
+}
+
+void
+delaytime (unsigned time)
+{
+       /* time and twait are in units of milliseconds */
+
+       unsigned twait;
+
+       switch (toupper (mtype)) {
+          case 'S': twait = time / 4; break;
+          case 'L': twait = 0; break;
+          default: twait = time / 8; break;
+       }
+
+       msleep (time - twait);
+       stopsound ();
+       msleep (twait);
+}
+
+char *
+delaynote (char *c)
+{
+       unsigned time = 0;
+
+       while (isdigit(*c)) time = time * 10 + (*c++ - '0');
+
+       if (!time) time = length;
+
+       time = (unsigned)(240000 / time / tempo);
+
+       while (*c == '.') { time = time * 3 / 2; c++; }
+
+       delaytime (time);
+
+       return c;
+}
+
+void
+initspeaker (void)
+{
+       tempo = 120, length = 4, octave = 3, mtype = 'N';
+}
+
+
+void
+play (char *tune)
+{
+       char *c, *n;
+       unsigned num;
+
+       for (c = tune; *c; ) {
+           sscanf (c + 1, "%u", &num);
+           for (n = c + 1; isdigit(*n); n++) /* do nothing */;
+           if (isspace(*c)) c++;
+           else switch (toupper(*c)) {
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+                   c = startnote (c);
+               case 'P':
+                   c = delaynote (++c);
+                   break;
+#if 0
+               case 'M': c++; mtype = *c; c++; break;
+               case 'T':
+                   if (num) tempo = num;
+                   else printf ("Zero Tempo (%s)!\n", c);
+                   c = n;
+                   break;
+               case 'L':
+                   if (num) length = num;
+                   else printf ("Zero Length (%s)!\n", c);
+                   c = n;
+                   break;
+               case 'O':
+                   if (num <= 7)
+                       octave = num;
+                   c = n;
+                   break;
+               case 'N':
+                   note (num);
+                   delaytime ((240000/length/tempo));
+                   c = n;
+                   break;
+               case '>': if (octave < 7) octave++; c++; break;
+               case '<': if (octave) octave--; c++; break;
+#endif
+               case ' ': c++; break;
+               default:
+                   printf ("Unrecognized play value (%s)!\n", c);
+                    return;
+           }
+       }
+}
+
+#ifndef TESTING
+void
+pc_speaker (struct obj *instr, char *tune)
+{
+    if (!iflags.usepcspeaker) return;
+    initspeaker ();
+    switch (instr->otyp)
+    {
+       case WOODEN_FLUTE:
+       case MAGIC_FLUTE:
+           octave = 5; /* up one octave */
+           break;
+       case TOOLED_HORN:
+       case FROST_HORN:
+       case FIRE_HORN:
+           octave = 2; /* drop two octaves */
+           break;
+       case BUGLE:
+           break;
+       case WOODEN_HARP:
+       case MAGIC_HARP:
+           length = 8;
+           mtype = 'L'; /* fast, legato */
+           break;
+    }
+    play (tune);
+}
+
+#else
+
+main ()
+{
+       char s[80];
+       int tool;
+
+       initspeaker();
+       printf ("1) flute\n2) horn\n3) harp\n4) other\n");
+       fgets (s, 80, stdin);
+       sscanf (s, "%d", &tool);
+       switch (tool) {
+       case 1: octave = 5; break;
+       case 2: octave = 2; break;
+       case 3: length = 8; mtype = 'L'; break;
+       default: break;
+       }
+       printf ("Enter tune:");
+       fgets(s, 80, stdin);
+       play (s);
+}
+#endif
+
+#endif /* PCMUSIC */
+
+/* sound.c */