// Emacs style mode select -*- C++ -*- //--------------------------------------------------------------------------- // // $Id: swsound.c,v 1.4 2003/04/05 22:55:11 fraggle Exp $ // // Copyright(C) 1984-2000 David L. Clark // Copyright(C) 2001-2003 Simon Howard // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. This program is distributed in the hope that // it will be useful, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // the GNU General Public License for more details. You should have // received a copy of the GNU General Public License along with this // program; if not, write to the Free Software Foundation, Inc., 59 Temple // Place - Suite 330, Boston, MA 02111-1307, USA. // //--------------------------------------------------------------------------- // // swsound - SW sound generation // //--------------------------------------------------------------------------- #include #include "pcsound.h" #include "timer.h" #include "sw.h" #include "swmain.h" #include "swsound.h" #define TIMER 0x40 #define PORTB 0x61 #define SNDSIZE 100 static int soundtype = 32767; /* Current sound type and */ static int soundparm = 32767; /* and priority parameter */ static OBJECTS *soundobj = NULL; /* Object making sound */ static unsigned lastfreq = 0; /* Last frequency used */ static OBJECTS *lastobj = NULL; /* Previous object making sound */ static void (*toneadj) () = NULL; /* Tone adjustment on clock tick */ static TONETAB tonetab[SNDSIZE]; /* Continuous tone table */ static TONETAB *frsttone, *freetone; /* Tone list and free list */ static unsigned soundticks; /* Ticks since last sound selection */ static int numexpls; /* Number of explosions currently */ /* active */ static int explplace; /* Place in explosion tune; */ static int explline; /* Line in explosion tune */ static unsigned expltone; /* Current explosion tone */ static int explticks; /* Ticks until note change */ static int exploctv; /* Octave */ //#define SOPWITH1_TUNE #ifdef SOPWITH1_TUNE static char *expltune[7] = { ">e4./d8/c4/d4/e4/d+4/e4/c4/d4/d4/d4/d1/", "d4./c8/b4/c4/d4/c+4/d4/b4/c4/c4/c4/c1/a4./a-8/a4/a-4/d4/d4/d2./a4./a-8/a4/a-4/e4/e4/e2./", "e4./d8/c4/d4/e4/d+4/e4/c4/d4/d4/d4/d2/c4/a4/", "d2/e2/g1/", "" }; #else static char *expltune[7] = { "b4/d8/d2/r16/c8/b8/a8/b4./c4./c+4./d4./", "e4/g8/g2/r16/>a8/a8/a2/r16/a2/r16/a8/c2/r16/", "b8/a8/b4/b4/a4./= 50) i = 0; return (seed[i++] % modulo); } static TONETAB *allocton() { register TONETAB *tt; if (!freetone) return 0; tt = freetone; freetone = tt->tt_next; tt->tt_next = frsttone; tt->tt_prev = NULL; if (frsttone) frsttone->tt_prev = tt; frsttone = tt; return frsttone; } static void deallton(TONETAB * ttp) { register TONETAB *tt = ttp; register TONETAB *ttb = tt->tt_prev; if (ttb) ttb->tt_next = tt->tt_next; else frsttone = tt->tt_next; ttb = tt->tt_next; if (ttb) ttb->tt_prev = tt->tt_prev; tt->tt_next = freetone; freetone = tt; } void initsndt() { register TONETAB *tt; register int i; for (i = 0, tt = tonetab; i < (SNDSIZE - 1); ++i, ++tt) tt->tt_next = tt + 1; tt->tt_next = NULL; frsttone = NULL; freetone = tonetab; } void stopsound(OBJECTS * ob) { TONETAB *tt = ob->ob_sound; if (!tt) return; if (ob->ob_type == EXPLOSION) --numexpls; else deallton(tt); ob->ob_sound = NULL; } void soundoff() { if (lastfreq) { // sdh: use the emulated sdl pc speaker code Speaker_Off(); lastfreq = 0; dispdbg = 0; } } static void tone(unsigned int freq) { if (!soundflg) return; if (lastfreq == freq) return; // sdh: use the emulated sdl pc speaker code Speaker_Output(freq); lastfreq = freq; dispdbg = freq; } // music note generation #define NOTEEND '/' #define UPOCTAVE '>' #define DOWNOCTAVE '<' #define SHARP '+' #define FLAT '-' #define DOT '.' #define REST 'R' void playnote() { static int noteindex[] = { 0, 2, 3, 5, 7, 8, 10 }; static int notefreq[] = { 440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831 }; static int durplace, test, freq, duration; static int index; static int indexadj; static char durstring[5]; static char charatplace, noteletter; static int noteoctavefactor; static int dottednote; BOOL firstplace = TRUE; indexadj = 0; durplace = 0; dottednote = 2; noteoctavefactor = 256; for (;;) { if (!line && !place) octavefactor = 256; charatplace = toupper(tune[line][place++]); if (!charatplace) { place = 0; charatplace = tune[++line][0]; if (!charatplace) { line = 0; } if (firstplace) continue; break; } firstplace = FALSE; if (charatplace == NOTEEND) break; test = isalpha(charatplace); if (test) { index = *(noteindex + (charatplace - 'A')); noteletter = charatplace; } else switch (charatplace) { case UPOCTAVE: octavefactor <<= 1; break; case DOWNOCTAVE: octavefactor >>= 1; break; case SHARP: indexadj++; break; case FLAT: indexadj--; break; case DOT: dottednote = 3; break; default: test = isdigit(charatplace); if (test) *(durstring + durplace++) = charatplace; break; } } durstring[durplace] = '\0'; duration = atoi(durstring); if (duration <= 0) duration = 4; duration = (1440 * dottednote / (60 * duration)) / 2; if (noteletter == REST) { tunefreq = 0; } else { index += indexadj; while (index < 0) { index += 12; noteoctavefactor /= 2; } while (index >= 12) { index -= 12; noteoctavefactor *= 2; } // sdh: soundmul and sounddiv were asm functions. i cant // read x86 asm so i have to guess freq = notefreq[index]; freq *= octavefactor; freq >>= 8; freq *= noteoctavefactor; freq >>= 8; // freq = soundmul( *(notefreq+index), octavefactor, noteoctavefactor ); tunefreq = 1331000 / freq; // tunefreq = sounddiv( 1331000L, freq ); } #ifdef SOPWITH1_TUNE tunedura = duration * 0.7; #else tunedura = duration; #endif } static void adjcont() { register TONETAB *tt = lastobj->ob_sound; if (tt) tone(tt->tt_tone + tt->tt_chng * soundticks); } static void adjshot() { static unsigned savefreq; if (lastfreq == 0xF000) tone(savefreq); else { savefreq = lastfreq; tone(0xF000); } } static void explnote() { line = explline; place = explplace; tune = expltune; octavefactor = exploctv; playnote(); explline = line; explplace = place; expltone = tunefreq; explticks += tunedura; exploctv = octavefactor; } static void adjexpl() { if (--explticks >= 0) return; explnote(); } static void titlnote() { line = titlline; place = titlplace; tune = expltune; octavefactor = titloctv; playnote(); titlline = line; titlplace = place; titltone = tunefreq; titlticks += tunedura; titloctv = octavefactor; soundoff(); tone(titltone); } static void adjtitl() { if (--titlticks >= 0) return; titlnote(); } static void soundadj() { ++soundticks; if (lastfreq && toneadj) (*toneadj) (); if (numexpls) adjexpl(); if (titleflg) adjtitl(); } void swsound() { register TONETAB *tt; tt = frsttone; while (tt) { tt->tt_tone += (tt->tt_chng * soundticks); tt = tt->tt_next; } soundticks = 0; titleflg = FALSE; switch (soundtype) { case 0: case 32767: default: soundoff(); lastobj = NULL; toneadj = NULL; break; case S_PLANE: if (soundparm) tone(0xF000 + soundparm * 0x1000); else tone(0xD000); lastobj = NULL; toneadj = NULL; break; case S_BOMB: if (soundobj == lastobj) break; toneadj = adjcont; lastobj = soundobj; adjcont(); break; case S_FALLING: if (soundobj == lastobj) break; toneadj = adjcont; lastobj = soundobj; adjcont(); break; case S_HIT: tone(swrand(2) ? 0x9000 : 0xF000); lastobj = NULL; toneadj = NULL; break; case S_EXPLOSION: tone(expltone); toneadj = NULL; lastobj = NULL; break; case S_SHOT: tone(0x1000); toneadj = adjshot; lastobj = NULL; break; } soundtype = soundparm = 32767; } void sound(int type, int parm, OBJECTS * ob) { // sdh 28/10/2001: moved code for title music setup here // if we are already playing the title music, ignore if (type == S_TITLE) { if (!titleflg) { titlline = 0; titlplace = 0; titlnote(); toneadj = NULL; lastobj = NULL; titleflg = TRUE; } } else if (type < soundtype) { soundtype = type; soundparm = parm; soundobj = ob; } else if (type == soundtype && parm < soundparm) { soundparm = parm; soundobj = ob; } } void initsound(OBJECTS * obp, int type) { register OBJECTS *ob; register TONETAB *tt; if ((ob = obp)->ob_sound) return; if (ob->ob_type == EXPLOSION) { if (++numexpls == 1) { explline = 0; explplace = 0; explnote(); } ob->ob_sound = (struct tt *) 1; return; } if ((tt = allocton())) { switch (type) { case S_BOMB: tt->tt_tone = 0x0300; tt->tt_chng = 8; break; case S_FALLING: tt->tt_tone = 0x1200; tt->tt_chng = -8; break; default: break; } ob->ob_sound = tt; return; } } // sdh: // in original sopwith this was done with interrupts // we dont have access to interrupts and its ugly in // any case, so instead we call this function occasionally // to check for updating the sound // in fact for continuity i have put a call to this // in the sdl sound callback function, so it is done // rather like the old interrupt system after all :) static int lastclock = 0; void swsndupdate() { int thisclock = Timer_GetMS(); if (thisclock > lastclock + 1000 / 18.2) { lastclock = thisclock; soundadj(); } } //--------------------------------------------------------------------------- // // $Log: swsound.c,v $ // Revision 1.4 2003/04/05 22:55:11 fraggle // Remove the FOREVER macro and some unused stuff from std.h // // Revision 1.3 2003/04/05 22:48:35 fraggle // Remove archaic swmach.h and all IBMPC/ATARI #defines // // Revision 1.2 2003/04/05 22:44:04 fraggle // Remove some useless functions from headers, make them static if they // are not used by other files // // Revision 1.1.1.1 2003/02/14 19:03:18 fraggle // Initial Sourceforge CVS import // // // sdh 14/2/2003: change license header to GPL // sdh 25/11/2001: remove intsoff, intson calls // sdh 21/10/2001: rearranged headers, added cvs tags // sdh 21/10/2001: reformatted with indent. adjusted some code by hand // to make more readable // sdh 20/10/2001: added #define to use sopwith 1 theme (extracted from // hexdump of sopwith1.exe) // sdh 19/10/2001: removed externs (now in headers) // shuffled some functions round to shut up compiler // sdh 18/10/2001: converted all functions to ANSI-style arguments // sdh ??/10/2001: use SDL digitally emulated PC speaker // // 87-03-10 Microsoft compiler. // 84-04-11 Development // //---------------------------------------------------------------------------